mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-01-27 09:24:47 +00:00
Merge branch 'master' into mc-1.14.x
This commit is contained in:
commit
906280225e
@ -1,14 +1,120 @@
|
|||||||
|
--[[- Interact with redstone attached to this computer.
|
||||||
|
|
||||||
|
The @{redstone} library exposes three "types" of redstone control:
|
||||||
|
- Binary input/output (@{setOutput}/@{getInput}): These simply check if a
|
||||||
|
redstone wire has any input or output. A signal strength of 1 and 15 are
|
||||||
|
treated the same.
|
||||||
|
- Analogue input/output (@{setAnalogueOutput}/@{getAnalogueInput}): These
|
||||||
|
work with the actual signal strength of the redstone wired, from 0 to 15.
|
||||||
|
- Bundled cables (@{setBundledOutput}/@{getBundledInput}): These interact with
|
||||||
|
"bundled" cables, such as those from Project:Red. These allow you to send
|
||||||
|
16 separate on/off signals. Each channel corresponds to a colour, with the
|
||||||
|
first being @{colors.white} and the last @{colors.black}.
|
||||||
|
|
||||||
|
Whenever a redstone input changes, a `redstone` event will be fired. This may
|
||||||
|
be used in or
|
||||||
|
|
||||||
|
This module may also be referred to as `rs`. For example, one may call
|
||||||
|
`rs.getSides()` instead of @{redstone.getSides}.
|
||||||
|
|
||||||
|
@module redstone
|
||||||
|
@usage Toggle the redstone signal above the computer every 0.5 seconds.
|
||||||
|
|
||||||
|
while true do
|
||||||
|
redstone.setOutput("top", not redstone.getOutput("top"))
|
||||||
|
sleep(0.5)
|
||||||
|
end
|
||||||
|
@usage Mimic a redstone comparator in [subtraction mode][comparator].
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local rear = rs.getAnalogueInput("back")
|
||||||
|
local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right"))
|
||||||
|
rs.setAnalogueOutput("front", math.max(rear - sides, 0))
|
||||||
|
|
||||||
|
os.pullEvent("redstone") -- Wait for a change to inputs.
|
||||||
|
end
|
||||||
|
|
||||||
|
[comparator]: https://minecraft.gamepedia.com/Redstone_Comparator#Subtract_signal_strength "Redstone Comparator on the Minecraft wiki."
|
||||||
|
]]
|
||||||
|
|
||||||
|
--- Returns a table containing the six sides of the computer. Namely, "top",
|
||||||
|
-- "bottom", "left", "right", "front" and "back".
|
||||||
|
--
|
||||||
|
-- @treturn { string... } A table of valid sides.
|
||||||
function getSides() end
|
function getSides() end
|
||||||
|
|
||||||
|
--- Turn the redstone signal of a specific side on or off.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to set.
|
||||||
|
-- @tparam boolean on Whether the redstone signal should be on or off. When on,
|
||||||
|
-- a signal strength of 15 is emitted.
|
||||||
function setOutput(side, on) end
|
function setOutput(side, on) end
|
||||||
|
|
||||||
|
--- Get the current redstone output of a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn boolean Whether the redstone output is on or off.
|
||||||
|
-- @see setOutput
|
||||||
function getOutput(side) end
|
function getOutput(side) end
|
||||||
|
|
||||||
|
--- Get the current redstone input of a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn boolean Whether the redstone input is on or off.
|
||||||
function getInput(side) end
|
function getInput(side) end
|
||||||
function setBundledOutput(side, output) end
|
|
||||||
function getBundledOutput(side) end
|
--- Set the redstone signal strength for a specific side.
|
||||||
function getBundledInput(side) end
|
--
|
||||||
function testBundledInput(side, mask) end
|
-- @tparam string side The side to set.
|
||||||
|
-- @tparam number value The signal strength, between 0 and 15.
|
||||||
|
-- @throws If `value` is not between 0 and 15.
|
||||||
function setAnalogOutput(side, value) end
|
function setAnalogOutput(side, value) end
|
||||||
setAnalogueOutput = setAnalogOutput
|
setAnalogueOutput = setAnalogOutput
|
||||||
|
|
||||||
|
--- Get the redstone output signal strength for a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn number The output signal strength, between 0 and 15.
|
||||||
|
-- @see setAnalogueOutput
|
||||||
function getAnalogOutput(sid) end
|
function getAnalogOutput(sid) end
|
||||||
getAnalogueOutput = getAnalogOutput
|
getAnalogueOutput = getAnalogOutput
|
||||||
|
|
||||||
|
--- Get the redstone input signal strength for a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn number The input signal strength, between 0 and 15.
|
||||||
function getAnalogInput(side) end
|
function getAnalogInput(side) end
|
||||||
getAnalogueInput = getAnalogInput
|
getAnalogueInput = getAnalogInput
|
||||||
|
|
||||||
|
--- Set the bundled cable output for a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to set.
|
||||||
|
-- @tparam number The colour bitmask to set.
|
||||||
|
-- @see colors.subtract For removing a colour from the bitmask.
|
||||||
|
-- @see colors.combine For adding a colour to the bitmask.
|
||||||
|
function setBundledOutput(side, output) end
|
||||||
|
|
||||||
|
--- Get the bundled cable output for a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn number The bundled cable's output.
|
||||||
|
function getBundledOutput(side) end
|
||||||
|
|
||||||
|
--- Get the bundled cable input for a specific side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to get.
|
||||||
|
-- @treturn number The bundled cable's input.
|
||||||
|
-- @see testBundledInput To determine if a specific colour is set.
|
||||||
|
function getBundledInput(side) end
|
||||||
|
|
||||||
|
--- Determine if a specific combination of colours are on for the given side.
|
||||||
|
--
|
||||||
|
-- @tparam string side The side to test.
|
||||||
|
-- @tparam number mask The mask to test.
|
||||||
|
-- @see getBundledInput
|
||||||
|
-- @see colors.combine For adding a colour to the bitmask.
|
||||||
|
-- @usage Check if @{colors.white} and @{colors.black} are on for above the
|
||||||
|
-- computer.
|
||||||
|
--
|
||||||
|
-- print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
|
||||||
|
function testBundledInput(side, mask) end
|
||||||
|
@ -73,12 +73,10 @@
|
|||||||
(/doc/stub/fs.lua
|
(/doc/stub/fs.lua
|
||||||
/doc/stub/http.lua
|
/doc/stub/http.lua
|
||||||
/doc/stub/os.lua
|
/doc/stub/os.lua
|
||||||
/doc/stub/redstone.lua
|
|
||||||
/doc/stub/term.lua
|
/doc/stub/term.lua
|
||||||
/doc/stub/turtle.lua
|
/doc/stub/turtle.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
|
/src/main/resources/*/computercraft/lua/rom/apis/io.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/apis/window.lua
|
/src/main/resources/*/computercraft/lua/rom/apis/window.lua)
|
||||||
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua)
|
|
||||||
|
|
||||||
(linters -doc:undocumented -doc:undocumented-arg))
|
(linters -doc:undocumented -doc:undocumented-arg))
|
||||||
|
|
||||||
@ -87,7 +85,6 @@
|
|||||||
(/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua
|
(/src/main/resources/*/computercraft/lua/rom/apis/textutils.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua
|
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/completion.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua
|
/src/main/resources/*/computercraft/lua/rom/modules/main/cc/shell/completion.lua
|
||||||
/src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua
|
|
||||||
/src/main/resources/*/computercraft/lua/rom/programs/shell.lua)
|
/src/main/resources/*/computercraft/lua/rom/programs/shell.lua)
|
||||||
(linters -doc:unresolved-reference))
|
(linters -doc:unresolved-reference))
|
||||||
|
|
||||||
|
@ -16,11 +16,11 @@ import static dan200.computercraft.api.lua.ArgumentHelper.*;
|
|||||||
|
|
||||||
public class RedstoneAPI implements ILuaAPI
|
public class RedstoneAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private IAPIEnvironment m_environment;
|
private final IAPIEnvironment environment;
|
||||||
|
|
||||||
public RedstoneAPI( IAPIEnvironment environment )
|
public RedstoneAPI( IAPIEnvironment environment )
|
||||||
{
|
{
|
||||||
m_environment = environment;
|
this.environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -63,31 +63,31 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
// setOutput
|
// setOutput
|
||||||
ComputerSide side = parseSide( args );
|
ComputerSide side = parseSide( args );
|
||||||
boolean output = getBoolean( args, 1 );
|
boolean output = getBoolean( args, 1 );
|
||||||
m_environment.setOutput( side, output ? 15 : 0 );
|
environment.setOutput( side, output ? 15 : 0 );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 2: // getOutput
|
case 2: // getOutput
|
||||||
return new Object[] { m_environment.getOutput( parseSide( args ) ) > 0 };
|
return new Object[] { environment.getOutput( parseSide( args ) ) > 0 };
|
||||||
case 3: // getInput
|
case 3: // getInput
|
||||||
return new Object[] { m_environment.getInput( parseSide( args ) ) > 0 };
|
return new Object[] { environment.getInput( parseSide( args ) ) > 0 };
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// setBundledOutput
|
// setBundledOutput
|
||||||
ComputerSide side = parseSide( args );
|
ComputerSide side = parseSide( args );
|
||||||
int output = getInt( args, 1 );
|
int output = getInt( args, 1 );
|
||||||
m_environment.setBundledOutput( side, output );
|
environment.setBundledOutput( side, output );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 5: // getBundledOutput
|
case 5: // getBundledOutput
|
||||||
return new Object[] { m_environment.getBundledOutput( parseSide( args ) ) };
|
return new Object[] { environment.getBundledOutput( parseSide( args ) ) };
|
||||||
case 6: // getBundledInput
|
case 6: // getBundledInput
|
||||||
return new Object[] { m_environment.getBundledInput( parseSide( args ) ) };
|
return new Object[] { environment.getBundledInput( parseSide( args ) ) };
|
||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// testBundledInput
|
// testBundledInput
|
||||||
ComputerSide side = parseSide( args );
|
ComputerSide side = parseSide( args );
|
||||||
int mask = getInt( args, 1 );
|
int mask = getInt( args, 1 );
|
||||||
int input = m_environment.getBundledInput( side );
|
int input = environment.getBundledInput( side );
|
||||||
return new Object[] { (input & mask) == mask };
|
return new Object[] { (input & mask) == mask };
|
||||||
}
|
}
|
||||||
case 8:
|
case 8:
|
||||||
@ -100,15 +100,15 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
throw new LuaException( "Expected number in range 0-15" );
|
throw new LuaException( "Expected number in range 0-15" );
|
||||||
}
|
}
|
||||||
m_environment.setOutput( side, output );
|
environment.setOutput( side, output );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 10:
|
case 10:
|
||||||
case 11: // getAnalogOutput/getAnalogueOutput
|
case 11: // getAnalogOutput/getAnalogueOutput
|
||||||
return new Object[] { m_environment.getOutput( parseSide( args ) ) };
|
return new Object[] { environment.getOutput( parseSide( args ) ) };
|
||||||
case 12:
|
case 12:
|
||||||
case 13: // getAnalogInput/getAnalogueInput
|
case 13: // getAnalogInput/getAnalogueInput
|
||||||
return new Object[] { m_environment.getInput( parseSide( args ) ) };
|
return new Object[] { environment.getInput( parseSide( args ) ) };
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,121 @@
|
|||||||
|
--- This provides a pure Lua implementation of the builtin @{require} function
|
||||||
|
-- and @{package} library.
|
||||||
|
--
|
||||||
|
-- Generally you do not need to use this module - it is injected into the
|
||||||
|
-- every program's environment. However, it may be useful when building a
|
||||||
|
-- custom shell or when running programs yourself.
|
||||||
|
--
|
||||||
|
-- @module cc.require
|
||||||
|
-- @usage Construct the package and require function, and insert them into a
|
||||||
|
-- custom environment.
|
||||||
|
--
|
||||||
|
-- local env = setmetatable({}, { __index = _ENV })
|
||||||
|
-- local r = require "cc.require"
|
||||||
|
-- env.require, env.package = r.make(env, "/")
|
||||||
|
|
||||||
|
local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")
|
||||||
|
local expect = expect.expect
|
||||||
|
|
||||||
|
local function preload(package)
|
||||||
|
return function(name)
|
||||||
|
if package.preload[name] then
|
||||||
|
return package.preload[name]
|
||||||
|
else
|
||||||
|
return nil, "no field package.preload['" .. name .. "']"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function from_file(package, env, dir)
|
||||||
|
return function(name)
|
||||||
|
local fname = string.gsub(name, "%.", "/")
|
||||||
|
local sError = ""
|
||||||
|
for pattern in string.gmatch(package.path, "[^;]+") do
|
||||||
|
local sPath = string.gsub(pattern, "%?", fname)
|
||||||
|
if sPath:sub(1, 1) ~= "/" then
|
||||||
|
sPath = fs.combine(dir, sPath)
|
||||||
|
end
|
||||||
|
if fs.exists(sPath) and not fs.isDir(sPath) then
|
||||||
|
local fnFile, sError = loadfile(sPath, nil, env)
|
||||||
|
if fnFile then
|
||||||
|
return fnFile, sPath
|
||||||
|
else
|
||||||
|
return nil, sError
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if #sError > 0 then
|
||||||
|
sError = sError .. "\n "
|
||||||
|
end
|
||||||
|
sError = sError .. "no file '" .. sPath .. "'"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, sError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function make_require(package)
|
||||||
|
local sentinel = {}
|
||||||
|
return function(name)
|
||||||
|
expect(1, name, "string")
|
||||||
|
|
||||||
|
if package.loaded[name] == sentinel then
|
||||||
|
error("loop or previous error loading module '" .. name .. "'", 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
if package.loaded[name] then
|
||||||
|
return package.loaded[name]
|
||||||
|
end
|
||||||
|
|
||||||
|
local sError = "module '" .. name .. "' not found:"
|
||||||
|
for _, searcher in ipairs(package.loaders) do
|
||||||
|
local loader = table.pack(searcher(name))
|
||||||
|
if loader[1] then
|
||||||
|
package.loaded[name] = sentinel
|
||||||
|
local result = loader[1](name, table.unpack(loader, 2, loader.n))
|
||||||
|
if result == nil then result = true end
|
||||||
|
|
||||||
|
package.loaded[name] = result
|
||||||
|
return result
|
||||||
|
else
|
||||||
|
sError = sError .. "\n " .. loader[2]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error(sError, 2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Build an implementation of Lua's @{package} library, and a @{require}
|
||||||
|
-- function to load modules within it.
|
||||||
|
--
|
||||||
|
-- @tparam table env The environment to load packages into.
|
||||||
|
-- @tparam string dir The directory that relative packages are loaded from.
|
||||||
|
-- @treturn function The new @{require} function.
|
||||||
|
-- @treturn table The new @{package} library.
|
||||||
|
local function make_package(env, dir)
|
||||||
|
expect(1, env, "table")
|
||||||
|
expect(2, dir, "string")
|
||||||
|
|
||||||
|
local package = {}
|
||||||
|
package.loaded = {
|
||||||
|
_G = _G,
|
||||||
|
bit32 = bit32,
|
||||||
|
coroutine = coroutine,
|
||||||
|
math = math,
|
||||||
|
package = package,
|
||||||
|
string = string,
|
||||||
|
table = table,
|
||||||
|
}
|
||||||
|
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
|
||||||
|
if turtle then
|
||||||
|
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
|
||||||
|
elseif commands then
|
||||||
|
package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua"
|
||||||
|
end
|
||||||
|
package.config = "/\n;\n?\n!\n-"
|
||||||
|
package.preload = {}
|
||||||
|
package.loaders = { preload(package), from_file(package, env, dir) }
|
||||||
|
|
||||||
|
return make_require(package), package
|
||||||
|
end
|
||||||
|
|
||||||
|
return { make = make_package }
|
@ -938,11 +938,23 @@ settings.define("motd.path", {
|
|||||||
description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]],
|
description = [[The path to load random messages from. Should be a colon (":") separated string of file paths.]],
|
||||||
type = "string",
|
type = "string",
|
||||||
})
|
})
|
||||||
|
|
||||||
settings.define("lua.warn_against_use_of_local", {
|
settings.define("lua.warn_against_use_of_local", {
|
||||||
default = true,
|
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 inaccessable on the next input.]],
|
||||||
type = "boolean",
|
type = "boolean",
|
||||||
})
|
})
|
||||||
|
settings.define("lua.function_args", {
|
||||||
|
default = true,
|
||||||
|
description = "Show function arguments when printing functions.",
|
||||||
|
type = "boolean",
|
||||||
|
})
|
||||||
|
settings.define("lua.function_source", {
|
||||||
|
default = false,
|
||||||
|
description = "Show where a function was defined when printing functions.",
|
||||||
|
type = "boolean",
|
||||||
|
})
|
||||||
|
|
||||||
if term.isColour() then
|
if term.isColour() then
|
||||||
settings.define("bios.use_multishell", {
|
settings.define("bios.use_multishell", {
|
||||||
default = true,
|
default = true,
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
* The Lua REPL warns when declaring locals (lupus590, exerro)
|
* The Lua REPL warns when declaring locals (lupus590, exerro)
|
||||||
* Add config to allow using command computers in survival.
|
* Add config to allow using command computers in survival.
|
||||||
* Add fs.isDriveRoot - checks if a path is the root of a drive.
|
* Add fs.isDriveRoot - checks if a path is the root of a drive.
|
||||||
|
* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default.
|
||||||
|
* Move the shell's `require`/`package` implementation to a separate `cc.require` module.
|
||||||
|
|
||||||
And several bug fixes:
|
And several bug fixes:
|
||||||
* Fix io.lines not accepting arguments.
|
* Fix io.lines not accepting arguments.
|
||||||
|
@ -7,6 +7,8 @@ New features in CC: Tweaked 1.88.0
|
|||||||
* The Lua REPL warns when declaring locals (lupus590, exerro)
|
* The Lua REPL warns when declaring locals (lupus590, exerro)
|
||||||
* Add config to allow using command computers in survival.
|
* Add config to allow using command computers in survival.
|
||||||
* Add fs.isDriveRoot - checks if a path is the root of a drive.
|
* Add fs.isDriveRoot - checks if a path is the root of a drive.
|
||||||
|
* `cc.pretty` can now display a function's arguments and where it was defined. The Lua REPL will show arguments by default.
|
||||||
|
* Move the shell's `require`/`package` implementation to a separate `cc.require` module.
|
||||||
|
|
||||||
And several bug fixes:
|
And several bug fixes:
|
||||||
* Fix io.lines not accepting arguments.
|
* Fix io.lines not accepting arguments.
|
||||||
|
@ -19,8 +19,12 @@
|
|||||||
-- local pretty = require "cc.pretty"
|
-- local pretty = require "cc.pretty"
|
||||||
-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
||||||
|
|
||||||
local expect = require "cc.expect".expect
|
local expect = require "cc.expect"
|
||||||
local type, getmetatable, setmetatable, colours, str_write = type, getmetatable, setmetatable, colours, write
|
local expect, field = expect.expect, expect.field
|
||||||
|
|
||||||
|
local type, getmetatable, setmetatable, colours, str_write, tostring = type, getmetatable, setmetatable, colours, write, tostring
|
||||||
|
local debug_info = type(debug) == "table" and type(debug.getinfo) == "function" and debug.getinfo
|
||||||
|
local debug_local = type(debug) == "table" and type(debug.getlocal) == "function" and debug.getlocal
|
||||||
|
|
||||||
--- @{table.insert} alternative, but with the length stored inline.
|
--- @{table.insert} alternative, but with the length stored inline.
|
||||||
local function append(out, value)
|
local function append(out, value)
|
||||||
@ -343,13 +347,38 @@ local function key_compare(a, b)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
local function pretty_impl(obj, tracking)
|
local function show_function(fn, options)
|
||||||
|
local info = debug_info and debug_info(fn, "Su")
|
||||||
|
|
||||||
|
-- Include function source position if available
|
||||||
|
local name
|
||||||
|
if options.function_source and info and info.short_src and info.linedefined and info.linedefined >= 1 then
|
||||||
|
name = "function<" .. info.short_src .. ":" .. info.linedefined .. ">"
|
||||||
|
else
|
||||||
|
name = tostring(fn)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Include arguments if a Lua function and if available. Lua will report "C"
|
||||||
|
-- functions as variadic.
|
||||||
|
if options.function_args and info and info.what == "Lua" and info.nparams and debug_local then
|
||||||
|
local args = {}
|
||||||
|
for i = 1, info.nparams do args[i] = debug_local(fn, i) or "?" end
|
||||||
|
if info.isvararg then args[#args + 1] = "..." end
|
||||||
|
name = name .. "(" .. table.concat(args, ", ") .. ")"
|
||||||
|
end
|
||||||
|
|
||||||
|
return name
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pretty_impl(obj, options, tracking)
|
||||||
local obj_type = type(obj)
|
local obj_type = type(obj)
|
||||||
if obj_type == "string" then
|
if obj_type == "string" then
|
||||||
local formatted = ("%q"):format(obj):gsub("\\\n", "\\n")
|
local formatted = ("%q"):format(obj):gsub("\\\n", "\\n")
|
||||||
return text(formatted, colours.red)
|
return text(formatted, colours.red)
|
||||||
elseif obj_type == "number" then
|
elseif obj_type == "number" then
|
||||||
return text(tostring(obj), colours.magenta)
|
return text(tostring(obj), colours.magenta)
|
||||||
|
elseif obj_type == "function" then
|
||||||
|
return text(show_function(obj, options), colours.lightGrey)
|
||||||
elseif obj_type ~= "table" or tracking[obj] then
|
elseif obj_type ~= "table" or tracking[obj] then
|
||||||
return text(tostring(obj), colours.lightGrey)
|
return text(tostring(obj), colours.lightGrey)
|
||||||
elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then
|
elseif getmetatable(obj) ~= nil and getmetatable(obj).__tostring then
|
||||||
@ -371,15 +400,15 @@ local function pretty_impl(obj, tracking)
|
|||||||
local v = obj[k]
|
local v = obj[k]
|
||||||
local ty = type(k)
|
local ty = type(k)
|
||||||
if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then
|
if ty == "number" and k % 1 == 0 and k >= 1 and k <= length then
|
||||||
append(doc, pretty_impl(v, tracking))
|
append(doc, pretty_impl(v, options, tracking))
|
||||||
elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
|
elseif ty == "string" and not keywords[k] and k:match("^[%a_][%a%d_]*$") then
|
||||||
append(doc, text(k .. " = "))
|
append(doc, text(k .. " = "))
|
||||||
append(doc, pretty_impl(v, tracking))
|
append(doc, pretty_impl(v, options, tracking))
|
||||||
else
|
else
|
||||||
append(doc, obracket)
|
append(doc, obracket)
|
||||||
append(doc, pretty_impl(k, tracking))
|
append(doc, pretty_impl(k, options, tracking))
|
||||||
append(doc, cbracket)
|
append(doc, cbracket)
|
||||||
append(doc, pretty_impl(v, tracking))
|
append(doc, pretty_impl(v, options, tracking))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -393,12 +422,24 @@ end
|
|||||||
-- This can then be rendered with @{write} or @{print}.
|
-- This can then be rendered with @{write} or @{print}.
|
||||||
--
|
--
|
||||||
-- @param obj The object to pretty-print.
|
-- @param obj The object to pretty-print.
|
||||||
|
-- @tparam[opt] { function_args = boolean, function_source = boolean } options
|
||||||
|
-- Controls how various properties are displayed.
|
||||||
|
-- - `function_args`: Show the arguments to a function if known (`false` by default).
|
||||||
|
-- - `function_source`: Show where the function was defined, instead of
|
||||||
|
-- `function: xxxxxxxx` (`false` by default).
|
||||||
-- @treturn Doc The object formatted as a document.
|
-- @treturn Doc The object formatted as a document.
|
||||||
-- @usage Display a table on the screen
|
-- @usage Display a table on the screen
|
||||||
-- local pretty = require "cc.pretty"
|
-- local pretty = require "cc.pretty"
|
||||||
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
|
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
|
||||||
local function pretty(obj)
|
local function pretty(obj, options)
|
||||||
return pretty_impl(obj, {})
|
expect(2, options, "table", "nil")
|
||||||
|
options = options or {}
|
||||||
|
|
||||||
|
local actual_options = {
|
||||||
|
function_source = field(options, "function_source", "boolean", "nil") or false,
|
||||||
|
function_args = field(options, "function_args", "boolean", "nil") or false,
|
||||||
|
}
|
||||||
|
return pretty_impl(obj, actual_options, {})
|
||||||
end
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -141,12 +141,12 @@ return {
|
|||||||
program = program,
|
program = program,
|
||||||
|
|
||||||
-- Re-export various other functions
|
-- Re-export various other functions
|
||||||
help = wrap(help.completeTopic),
|
help = wrap(help.completeTopic), --- Wraps @{help.completeTopic} as a @{build} compatible function.
|
||||||
choice = wrap(completion.choice),
|
choice = wrap(completion.choice), --- Wraps @{cc.completion.choice} as a @{build} compatible function.
|
||||||
peripheral = wrap(completion.peripheral),
|
peripheral = wrap(completion.peripheral), --- Wraps @{cc.completion.peripheral} as a @{build} compatible function.
|
||||||
side = wrap(completion.side),
|
side = wrap(completion.side), --- Wraps @{cc.completion.side} as a @{build} compatible function.
|
||||||
setting = wrap(completion.setting),
|
setting = wrap(completion.setting), --- Wraps @{cc.completion.setting} as a @{build} compatible function.
|
||||||
command = wrap(completion.command),
|
command = wrap(completion.command), --- Wraps @{cc.completion.command} as a @{build} compatible function.
|
||||||
|
|
||||||
build = build,
|
build = build,
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,10 @@ while bRunning do
|
|||||||
local n = 1
|
local n = 1
|
||||||
while n < tResults.n or n <= nForcePrint do
|
while n < tResults.n or n <= nForcePrint do
|
||||||
local value = tResults[n + 1]
|
local value = tResults[n + 1]
|
||||||
local ok, serialised = pcall(pretty.pretty, value)
|
local ok, serialised = pcall(pretty.pretty, value, {
|
||||||
|
function_args = settings.get("lua.function_args"),
|
||||||
|
function_source = settings.get("lua.function_source"),
|
||||||
|
})
|
||||||
if ok then
|
if ok then
|
||||||
pretty.print(serialised)
|
pretty.print(serialised)
|
||||||
else
|
else
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
-- @module[module] shell
|
-- @module[module] shell
|
||||||
|
|
||||||
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
local expect = dofile("rom/modules/main/cc/expect.lua").expect
|
||||||
|
local make_package = dofile("rom/modules/main/cc/require.lua").make
|
||||||
|
|
||||||
local multishell = multishell
|
local multishell = multishell
|
||||||
local parentShell = shell
|
local parentShell = shell
|
||||||
@ -28,94 +29,10 @@ local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {}
|
|||||||
local tProgramStack = {}
|
local tProgramStack = {}
|
||||||
|
|
||||||
local shell = {} --- @export
|
local shell = {} --- @export
|
||||||
local function createShellEnv(sDir)
|
local function createShellEnv(dir)
|
||||||
local tEnv = {}
|
local env = { shell = shell, multishell = multishell }
|
||||||
tEnv.shell = shell
|
env.require, env.package = make_package(env, dir)
|
||||||
tEnv.multishell = multishell
|
return env
|
||||||
|
|
||||||
local package = {}
|
|
||||||
package.loaded = {
|
|
||||||
_G = _G,
|
|
||||||
bit32 = bit32,
|
|
||||||
coroutine = coroutine,
|
|
||||||
math = math,
|
|
||||||
package = package,
|
|
||||||
string = string,
|
|
||||||
table = table,
|
|
||||||
}
|
|
||||||
package.path = "?;?.lua;?/init.lua;/rom/modules/main/?;/rom/modules/main/?.lua;/rom/modules/main/?/init.lua"
|
|
||||||
if turtle then
|
|
||||||
package.path = package.path .. ";/rom/modules/turtle/?;/rom/modules/turtle/?.lua;/rom/modules/turtle/?/init.lua"
|
|
||||||
elseif commands then
|
|
||||||
package.path = package.path .. ";/rom/modules/command/?;/rom/modules/command/?.lua;/rom/modules/command/?/init.lua"
|
|
||||||
end
|
|
||||||
package.config = "/\n;\n?\n!\n-"
|
|
||||||
package.preload = {}
|
|
||||||
package.loaders = {
|
|
||||||
function(name)
|
|
||||||
if package.preload[name] then
|
|
||||||
return package.preload[name]
|
|
||||||
else
|
|
||||||
return nil, "no field package.preload['" .. name .. "']"
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
function(name)
|
|
||||||
local fname = string.gsub(name, "%.", "/")
|
|
||||||
local sError = ""
|
|
||||||
for pattern in string.gmatch(package.path, "[^;]+") do
|
|
||||||
local sPath = string.gsub(pattern, "%?", fname)
|
|
||||||
if sPath:sub(1, 1) ~= "/" then
|
|
||||||
sPath = fs.combine(sDir, sPath)
|
|
||||||
end
|
|
||||||
if fs.exists(sPath) and not fs.isDir(sPath) then
|
|
||||||
local fnFile, sError = loadfile(sPath, nil, tEnv)
|
|
||||||
if fnFile then
|
|
||||||
return fnFile, sPath
|
|
||||||
else
|
|
||||||
return nil, sError
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if #sError > 0 then
|
|
||||||
sError = sError .. "\n "
|
|
||||||
end
|
|
||||||
sError = sError .. "no file '" .. sPath .. "'"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil, sError
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
|
|
||||||
local sentinel = {}
|
|
||||||
local function require(name)
|
|
||||||
expect(1, name, "string")
|
|
||||||
if package.loaded[name] == sentinel then
|
|
||||||
error("loop or previous error loading module '" .. name .. "'", 0)
|
|
||||||
end
|
|
||||||
if package.loaded[name] then
|
|
||||||
return package.loaded[name]
|
|
||||||
end
|
|
||||||
|
|
||||||
local sError = "module '" .. name .. "' not found:"
|
|
||||||
for _, searcher in ipairs(package.loaders) do
|
|
||||||
local loader = table.pack(searcher(name))
|
|
||||||
if loader[1] then
|
|
||||||
package.loaded[name] = sentinel
|
|
||||||
local result = loader[1](name, table.unpack(loader, 2, loader.n))
|
|
||||||
if result == nil then result = true end
|
|
||||||
|
|
||||||
package.loaded[name] = result
|
|
||||||
return result
|
|
||||||
else
|
|
||||||
sError = sError .. "\n " .. loader[2]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
error(sError, 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
tEnv.package = package
|
|
||||||
tEnv.require = require
|
|
||||||
|
|
||||||
return tEnv
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Colours
|
-- Colours
|
||||||
|
92
src/test/resources/test-rom/spec/apis/redstone_spec.lua
Normal file
92
src/test/resources/test-rom/spec/apis/redstone_spec.lua
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
local function it_side(func, ...)
|
||||||
|
local arg = table.pack(...)
|
||||||
|
it("requires a specific side", function()
|
||||||
|
expect.error(func, 0):eq("bad argument #1 (string expected, got number)")
|
||||||
|
expect.error(func, "blah", table.unpack(arg)):eq("Invalid side.")
|
||||||
|
|
||||||
|
func("top", table.unpack(arg))
|
||||||
|
func("Top", table.unpack(arg))
|
||||||
|
func("toP", table.unpack(arg))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("The redstone library", function()
|
||||||
|
describe("redstone.setOutput", function()
|
||||||
|
it_side(redstone.setOutput, false)
|
||||||
|
|
||||||
|
it("sets the output strength correctly", function()
|
||||||
|
redstone.setOutput("top", false)
|
||||||
|
expect(redstone.getAnalogueOutput("top")):eq(0)
|
||||||
|
|
||||||
|
redstone.setOutput("top", true)
|
||||||
|
expect(redstone.getAnalogueOutput("top")):eq(15)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getOutput", function()
|
||||||
|
it_side(redstone.getOutput)
|
||||||
|
|
||||||
|
it("gets the output strength correctly", function()
|
||||||
|
redstone.setAnalogueOutput("top", 0)
|
||||||
|
expect(redstone.getOutput("top")):eq(false)
|
||||||
|
|
||||||
|
redstone.setAnalogueOutput("top", 1)
|
||||||
|
expect(redstone.getOutput("top")):eq(true)
|
||||||
|
|
||||||
|
redstone.setAnalogueOutput("top", 15)
|
||||||
|
expect(redstone.getOutput("top")):eq(true)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getInput", function()
|
||||||
|
it_side(redstone.getInput)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.setAnalogueOutput", function()
|
||||||
|
it_side(redstone.setAnalogueOutput, 0)
|
||||||
|
|
||||||
|
it("checks the strength parameter", function()
|
||||||
|
expect.error(redstone.setAnalogueOutput, "top", true):eq("bad argument #2 (number expected, got boolean)")
|
||||||
|
expect.error(redstone.setAnalogueOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)")
|
||||||
|
expect.error(redstone.setAnalogueOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)")
|
||||||
|
expect.error(redstone.setAnalogueOutput, "top", -1):eq("Expected number in range 0-15")
|
||||||
|
expect.error(redstone.setAnalogueOutput, "top", 16):eq("Expected number in range 0-15")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getAnalogueOutput", function()
|
||||||
|
it_side(redstone.getAnalogueOutput)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getAnalogueInput", function()
|
||||||
|
it_side(redstone.getAnalogueInput)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.setBundledOutput", function()
|
||||||
|
it_side(redstone.setBundledOutput, 0)
|
||||||
|
|
||||||
|
it("checks the mask parameter", function()
|
||||||
|
expect.error(redstone.setBundledOutput, "top", true):eq("bad argument #2 (number expected, got boolean)")
|
||||||
|
expect.error(redstone.setBundledOutput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)")
|
||||||
|
expect.error(redstone.setBundledOutput, "top", math.huge):eq("bad argument #2 (number expected, got inf)")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getBundledOutput", function()
|
||||||
|
it_side(redstone.getBundledOutput)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.getBundledInput", function()
|
||||||
|
it_side(redstone.getBundledInput)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("redstone.testBundledInput", function()
|
||||||
|
it_side(redstone.testBundledInput, 0)
|
||||||
|
|
||||||
|
it("checks the mask parameter", function()
|
||||||
|
expect.error(redstone.testBundledInput, "top", true):eq("bad argument #2 (number expected, got boolean)")
|
||||||
|
expect.error(redstone.testBundledInput, "top", 0 / 0):eq("bad argument #2 (number expected, got nan)")
|
||||||
|
expect.error(redstone.testBundledInput, "top", math.huge):eq("bad argument #2 (number expected, got inf)")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
@ -165,7 +165,7 @@ describe("cc.pretty", function()
|
|||||||
describe("pretty", function()
|
describe("pretty", function()
|
||||||
-- We make use of "render" here, as it's considerably easier than checking against the actual structure.
|
-- We make use of "render" here, as it's considerably easier than checking against the actual structure.
|
||||||
-- However, it does also mean our tests are less unit-like.
|
-- However, it does also mean our tests are less unit-like.
|
||||||
local function pretty(x, width) return pp.render(pp.pretty(x), width) end
|
local function pretty(x, width, options) return pp.render(pp.pretty(x, options), width) end
|
||||||
|
|
||||||
describe("tables", function()
|
describe("tables", function()
|
||||||
it("displays empty tables", function()
|
it("displays empty tables", function()
|
||||||
@ -201,8 +201,21 @@ describe("cc.pretty", function()
|
|||||||
expect(pretty("hello\nworld")):eq('"hello\\nworld"')
|
expect(pretty("hello\nworld")):eq('"hello\\nworld"')
|
||||||
end)
|
end)
|
||||||
|
|
||||||
it("shows functions", function()
|
describe("functions", function()
|
||||||
expect(pretty(pretty)):eq(tostring(pretty))
|
it("shows functions", function()
|
||||||
|
expect(pretty(pretty)):eq(tostring(pretty))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("shows function arguments", function()
|
||||||
|
local f = function(a, ...) end
|
||||||
|
expect(pretty(f, nil, { function_args = true })):eq(tostring(f) .. "(a, ...)")
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("shows the function source", function()
|
||||||
|
local f = function(a, ...) end
|
||||||
|
expect(pretty(f, nil, { function_source = true }))
|
||||||
|
:str_match("^function<.*pretty_spec%.lua:%d+>$")
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -0,0 +1,79 @@
|
|||||||
|
describe("cc.require", function()
|
||||||
|
local r = require "cc.require"
|
||||||
|
local function mk()
|
||||||
|
local env = setmetatable({}, { __index = _ENV })
|
||||||
|
env.require, env.package = r.make({}, "/test-files/modules")
|
||||||
|
return env.require, env.package
|
||||||
|
end
|
||||||
|
|
||||||
|
local function setup(path, contents)
|
||||||
|
fs.delete("/test-files/modules")
|
||||||
|
io.open(path, "w"):write(contents):close()
|
||||||
|
end
|
||||||
|
|
||||||
|
describe("require", function()
|
||||||
|
it("errors on recursive modules", function()
|
||||||
|
local require, package = mk()
|
||||||
|
package.preload.pkg = function() require "pkg" end
|
||||||
|
expect.error(require, "pkg"):eq("loop or previous error loading module 'pkg'")
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("supplies the current module name", function()
|
||||||
|
local require, package = mk()
|
||||||
|
package.preload.pkg = table.pack
|
||||||
|
expect(require("pkg")):same { n = 1, "pkg" }
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("returns true instead of nil", function()
|
||||||
|
local require, package = mk()
|
||||||
|
package.preload.pkg = function() return nil end
|
||||||
|
expect(require("pkg")):eq(true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("returns a constant value", function()
|
||||||
|
local require, package = mk()
|
||||||
|
package.preload.pkg = function() return {} end
|
||||||
|
expect(require("pkg")):eq(require("pkg"))
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("returns an error on not-found modules", function()
|
||||||
|
local require, package = mk()
|
||||||
|
package.path = "/?;/?.lua"
|
||||||
|
expect.error(require, "pkg"):eq(
|
||||||
|
"module 'pkg' not found:\n" ..
|
||||||
|
" no field package.preload['pkg']\n" ..
|
||||||
|
" no file '/pkg'\n" ..
|
||||||
|
" no file '/pkg.lua'")
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
describe("the file loader", function()
|
||||||
|
local function get(path)
|
||||||
|
local require, package = mk()
|
||||||
|
if path then package.path = path end
|
||||||
|
return require
|
||||||
|
end
|
||||||
|
|
||||||
|
it("works on absolute paths", function()
|
||||||
|
local require = get("/test-files/?.lua")
|
||||||
|
setup("test-files/some_module.lua", "return 123")
|
||||||
|
expect(require("some_module")):eq(123)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works on relative paths", function()
|
||||||
|
local require = get("?.lua")
|
||||||
|
setup("test-files/modules/some_module.lua", "return 123")
|
||||||
|
expect(require("some_module")):eq(123)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("fails on syntax errors", function()
|
||||||
|
local require = get("?.lua")
|
||||||
|
setup("test-files/modules/some_module.lua", "1")
|
||||||
|
expect.error(require, "some_module"):str_match(
|
||||||
|
"^module 'some_module' not found:\n" ..
|
||||||
|
" no field package.preload%['some_module'%]\n" ..
|
||||||
|
" [^:]*some_module.lua:1: unexpected symbol near '1'$"
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user