mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-30 13:13:00 +00:00
Merge branch 'mc-1.15.x' into mc-1.16.x
This commit is contained in:
@@ -338,8 +338,8 @@ function read(_sReplaceChar, _tHistory, _fnComplete, _sDefault)
|
||||
redraw()
|
||||
|
||||
elseif sEvent == "key" then
|
||||
if param == keys.enter then
|
||||
-- Enter
|
||||
if param == keys.enter or param == keys.numPadEnter then
|
||||
-- Enter/Numpad Enter
|
||||
if nCompletion then
|
||||
clear()
|
||||
uncomplete()
|
||||
@@ -523,6 +523,16 @@ function os.run(_tEnv, _sPath, ...)
|
||||
|
||||
local tEnv = _tEnv
|
||||
setmetatable(tEnv, { __index = _G })
|
||||
|
||||
if settings.get("bios.strict_globals", false) then
|
||||
-- load will attempt to set _ENV on this environment, which
|
||||
-- throws an error with this protection enabled. Thus we set it here first.
|
||||
tEnv._ENV = tEnv
|
||||
getmetatable(tEnv).__newindex = function(_, name)
|
||||
error("Attempt to create global " .. tostring(name), 2)
|
||||
end
|
||||
end
|
||||
|
||||
local fnFile, err = loadfile(_sPath, nil, tEnv)
|
||||
if fnFile then
|
||||
local ok, err = pcall(fnFile, ...)
|
||||
@@ -954,6 +964,11 @@ settings.define("lua.function_source", {
|
||||
description = "Show where a function was defined when printing functions.",
|
||||
type = "boolean",
|
||||
})
|
||||
settings.define("bios.strict_globals", {
|
||||
default = false,
|
||||
description = "Prevents assigning variables into a program's environment. Make sure you use the local keyword or assign to _G explicitly.",
|
||||
type = "boolean",
|
||||
})
|
||||
|
||||
if term.isColour() then
|
||||
settings.define("bios.use_multishell", {
|
||||
|
||||
@@ -270,7 +270,7 @@ end
|
||||
-- @treturn number The combined hexadecimal colour.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0.7, 0.2, 0.6)
|
||||
-- colors.packRGB(0.7, 0.2, 0.6)
|
||||
-- -- => 0xb23399
|
||||
-- ```
|
||||
function packRGB(r, g, b)
|
||||
@@ -291,7 +291,7 @@ end
|
||||
-- @treturn number The blue channel, will be between 0 and 1.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0xb23399)
|
||||
-- colors.unpackRGB(0xb23399)
|
||||
-- -- => 0.7, 0.2, 0.6
|
||||
-- ```
|
||||
-- @see colors.packRGB
|
||||
@@ -317,12 +317,12 @@ end
|
||||
-- @deprecated Use @{packRGB} or @{unpackRGB} directly.
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0xb23399)
|
||||
-- colors.rgb8(0xb23399)
|
||||
-- -- => 0.7, 0.2, 0.6
|
||||
-- ```
|
||||
-- @usage
|
||||
-- ```lua
|
||||
-- colors.rgb(0.7, 0.2, 0.6)
|
||||
-- colors.rgb8(0.7, 0.2, 0.6)
|
||||
-- -- => 0xb23399
|
||||
-- ```
|
||||
function rgb8(r, g, b)
|
||||
|
||||
@@ -22,7 +22,7 @@ end
|
||||
--
|
||||
-- @tparam string name The name of the disk drive.
|
||||
-- @treturn boolean If something is in the disk drive.
|
||||
-- @usage disk.isPresent(false)
|
||||
-- @usage disk.isPresent("top")
|
||||
function isPresent(name)
|
||||
if isDrive(name) then
|
||||
return peripheral.call(name, "isDiskPresent")
|
||||
|
||||
@@ -32,7 +32,7 @@ end
|
||||
-- @tparam string topic The topic to find
|
||||
-- @treturn string|nil The path to the given topic's help file, or `nil` if it
|
||||
-- cannot be found.
|
||||
-- @usage print(help.lookup("disk"))
|
||||
-- @usage help.lookup("disk")
|
||||
function lookup(_sTopic)
|
||||
expect(1, _sTopic, "string")
|
||||
-- Look on the path variable
|
||||
@@ -52,6 +52,7 @@ end
|
||||
--- Returns a list of topics that can be looked up and/or displayed.
|
||||
--
|
||||
-- @treturn table A list of topics in alphabetical order.
|
||||
-- @usage help.topics()
|
||||
function topics()
|
||||
-- Add index
|
||||
local tItems = {
|
||||
|
||||
@@ -145,6 +145,7 @@ keys.cimcumflex = keys.circumflex --- @local
|
||||
--
|
||||
-- @tparam number code The key code to look up.
|
||||
-- @treturn string|nil The name of the key, or `nil` if not a valid key code.
|
||||
-- @usage keys.getName(keys.enter)
|
||||
function getName(_nKey)
|
||||
expect(1, _nKey, "number")
|
||||
return tKeys[_nKey]
|
||||
|
||||
@@ -64,6 +64,10 @@ end
|
||||
--
|
||||
-- @treturn table|nil The parsed image data, suitable for use with
|
||||
-- @{paintutils.drawImage}, or `nil` if the file does not exist.
|
||||
-- @usage Load an image and draw it.
|
||||
--
|
||||
-- local image = paintutils.loadImage("test-image.nfp")
|
||||
-- paintutils.drawImage(image, term.getCursorPos())
|
||||
function loadImage(path)
|
||||
expect(1, path, "string")
|
||||
|
||||
@@ -107,6 +111,7 @@ end
|
||||
-- @tparam number endY The end y position of the line.
|
||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
||||
-- the current background colour if not specified.
|
||||
-- @usage paintutils.drawLine(2, 3, 30, 7, colors.red)
|
||||
function drawLine(startX, startY, endX, endY, colour)
|
||||
expect(1, startX, "number")
|
||||
expect(2, startY, "number")
|
||||
@@ -170,6 +175,7 @@ end
|
||||
-- @tparam number endY The end y position of the line.
|
||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
||||
-- the current background colour if not specified.
|
||||
-- @usage paintutils.drawBox(2, 3, 30, 7, colors.red)
|
||||
function drawBox(startX, startY, endX, endY, nColour)
|
||||
expect(1, startX, "number")
|
||||
expect(2, startY, "number")
|
||||
@@ -222,6 +228,7 @@ end
|
||||
-- @tparam number endY The end y position of the line.
|
||||
-- @tparam[opt] number colour The @{colors|color} of this pixel. This will be
|
||||
-- the current background colour if not specified.
|
||||
-- @usage paintutils.drawFilledBox(2, 3, 30, 7, colors.red)
|
||||
function drawFilledBox(startX, startY, endX, endY, nColour)
|
||||
expect(1, startX, "number")
|
||||
expect(2, startY, "number")
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
--- Provides a simple implementation of multitasking.
|
||||
--
|
||||
-- Functions are not actually executed simultaniously, but rather this API will
|
||||
-- automatically switch between them whenever they yield (eg whenever they call
|
||||
-- @{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or
|
||||
-- functions that call that, etc - basically, anything that causes the function
|
||||
-- to "pause").
|
||||
--
|
||||
-- Each function executed in "parallel" gets its own copy of the event queue,
|
||||
-- and so "event consuming" functions (again, mostly anything that causes the
|
||||
-- script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API,
|
||||
-- etc) can safely be used in one without affecting the event queue accessed by
|
||||
-- the other.
|
||||
--
|
||||
-- @module parallel
|
||||
--[[- Provides a simple implementation of multitasking.
|
||||
|
||||
Functions are not actually executed simultaniously, but rather this API will
|
||||
automatically switch between them whenever they yield (eg whenever they call
|
||||
@{coroutine.yield}, or functions that call that - eg `os.pullEvent` - or
|
||||
functions that call that, etc - basically, anything that causes the function
|
||||
to "pause").
|
||||
|
||||
Each function executed in "parallel" gets its own copy of the event queue,
|
||||
and so "event consuming" functions (again, mostly anything that causes the
|
||||
script to pause - eg `sleep`, `rednet.receive`, most of the `turtle` API,
|
||||
etc) can safely be used in one without affecting the event queue accessed by
|
||||
the other.
|
||||
|
||||
@module parallel
|
||||
]]
|
||||
|
||||
local function create(...)
|
||||
local tFns = table.pack(...)
|
||||
@@ -70,21 +71,53 @@ local function runUntilLimit(_routines, _limit)
|
||||
end
|
||||
end
|
||||
|
||||
--- Switches between execution of the functions, until any of them
|
||||
-- finishes. If any of the functions errors, the message is propagated upwards
|
||||
-- from the @{parallel.waitForAny} call.
|
||||
--
|
||||
-- @tparam function ... The functions this task will run
|
||||
--[[- Switches between execution of the functions, until any of them
|
||||
finishes. If any of the functions errors, the message is propagated upwards
|
||||
from the @{parallel.waitForAny} call.
|
||||
|
||||
@tparam function ... The functions this task will run
|
||||
@usage Print a message every second until the `q` key is pressed.
|
||||
|
||||
local function tick()
|
||||
while true do
|
||||
os.sleep(1)
|
||||
print("Tick")
|
||||
end
|
||||
end
|
||||
local function wait_for_q()
|
||||
repeat
|
||||
local _, key = os.pullEvent("key")
|
||||
until key == keys.q
|
||||
print("Q was pressed!")
|
||||
end
|
||||
|
||||
parallel.waitForAny(tick, wait_for_q)
|
||||
print("Everything done!")
|
||||
]]
|
||||
function waitForAny(...)
|
||||
local routines = create(...)
|
||||
return runUntilLimit(routines, #routines - 1)
|
||||
end
|
||||
|
||||
--- Switches between execution of the functions, until all of them are
|
||||
-- finished. If any of the functions errors, the message is propagated upwards
|
||||
-- from the @{parallel.waitForAll} call.
|
||||
--
|
||||
-- @tparam function ... The functions this task will run
|
||||
--[[- Switches between execution of the functions, until all of them are
|
||||
finished. If any of the functions errors, the message is propagated upwards
|
||||
from the @{parallel.waitForAll} call.
|
||||
|
||||
@tparam function ... The functions this task will run
|
||||
@usage Start off two timers and wait for them both to run.
|
||||
|
||||
local function a()
|
||||
os.sleep(1)
|
||||
print("A is done")
|
||||
end
|
||||
local function b()
|
||||
os.sleep(3)
|
||||
print("B is done")
|
||||
end
|
||||
|
||||
parallel.waitForAll(a, b)
|
||||
print("Everything done!")
|
||||
]]
|
||||
function waitForAll(...)
|
||||
local routines = create(...)
|
||||
return runUntilLimit(routines, 0)
|
||||
|
||||
@@ -191,7 +191,7 @@ end
|
||||
-- filter function, which takes the peripheral's name and wrapped table
|
||||
-- and returns if it should be included in the result.
|
||||
-- @treturn table... 0 or more wrapped peripherals matching the given filters.
|
||||
-- @usage local monitors = { peripheral.find("monitor") }
|
||||
-- @usage { peripheral.find("monitor") }
|
||||
-- @usage peripheral.find("modem", rednet.open)
|
||||
function find(ty, filter)
|
||||
expect(1, ty, "string")
|
||||
|
||||
@@ -9,7 +9,7 @@ local expect, field = expect.expect, expect.field
|
||||
--- Slowly writes string text at current cursor position,
|
||||
-- character-by-character.
|
||||
--
|
||||
-- Like @{write}, this does not insert a newline at the end.
|
||||
-- Like @{_G.write}, this does not insert a newline at the end.
|
||||
--
|
||||
-- @tparam string sText The the text to write to the screen
|
||||
-- @tparam[opt] number nRate The number of characters to write each second,
|
||||
@@ -119,8 +119,8 @@ end
|
||||
-- displayed before prompting.
|
||||
-- @treturn number The number of lines printed.
|
||||
-- @usage
|
||||
-- local width, height = term.getSize()
|
||||
-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2)
|
||||
-- local width, height = term.getSize()
|
||||
-- textutils.pagedPrint(("This is a rather verbose dose of repetition.\n"):rep(30), height - 2)
|
||||
function pagedPrint(_sText, _nFreeLines)
|
||||
expect(2, _nFreeLines, "number", "nil")
|
||||
-- Setup a redirector
|
||||
@@ -163,10 +163,11 @@ local function tabulateCommon(bPaged, ...)
|
||||
for n, t in ipairs(tAll) do
|
||||
if type(t) == "table" then
|
||||
for nu, sItem in pairs(t) do
|
||||
if type(sItem) ~= "string" then
|
||||
error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. type(sItem) .. ")", 3)
|
||||
local ty = type(sItem)
|
||||
if ty ~= "string" and ty ~= "number" then
|
||||
error("bad argument #" .. n .. "." .. nu .. " (expected string, got " .. ty .. ")", 3)
|
||||
end
|
||||
nMaxLen = math.max(#sItem + 1, nMaxLen)
|
||||
nMaxLen = math.max(#tostring(sItem) + 1, nMaxLen)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -706,7 +707,7 @@ unserialiseJSON = unserialise_json
|
||||
--
|
||||
-- @tparam string str The string to encode
|
||||
-- @treturn string The encoded string.
|
||||
-- @usage print("https://example.com/?view=" .. textutils.urlEncode(read()))
|
||||
-- @usage print("https://example.com/?view=" .. textutils.urlEncode("some text&things"))
|
||||
function urlEncode(str)
|
||||
expect(1, str, "string")
|
||||
if str then
|
||||
@@ -744,8 +745,8 @@ local tEmpty = {}
|
||||
--
|
||||
-- @treturn { string... } The (possibly empty) list of completions.
|
||||
-- @see shell.setCompletionFunction
|
||||
-- @see read
|
||||
-- @usage textutils.complete( "pa", getfenv() )
|
||||
-- @see _G.read
|
||||
-- @usage textutils.complete( "pa", _ENV )
|
||||
function complete(sSearchText, tSearchTable)
|
||||
expect(1, sSearchText, "string")
|
||||
expect(2, tSearchTable, "table", "nil")
|
||||
|
||||
@@ -1,3 +1,25 @@
|
||||
# New features in CC: Tweaked 1.95.0
|
||||
|
||||
* Optimise the paint program's initial render.
|
||||
* Several documentation improvments (Gibbo3771, MCJack123).
|
||||
* `fs.combine` now accepts multiple arguments.
|
||||
* Add a setting (`bios.strict_globals`) to error when accidentally declaring a global. (Lupus590).
|
||||
* Add an improved help viewer which allows scrolling up and down (MCJack123).
|
||||
* Add `cc.strings` module, with utilities for wrapping text (Lupus590).
|
||||
* The `clear` program now allows resetting the palette too (Luca0208).
|
||||
|
||||
And several bug fixes:
|
||||
* Fix memory leak in generic peripherals.
|
||||
* Fix crash when a turtle is broken while being ticked.
|
||||
* `textutils.*tabulate` now accepts strings _or_ numbers.
|
||||
* We now deny _all_ local IPs, using the magic `$private` host. Previously the IPv6 loopback interface was not blocked.
|
||||
* Fix crash when rendering monitors if the block has not yet been synced. You will need to regenerate the config file to apply this change.
|
||||
* `read` now supports numpad enter (TheWireLord)
|
||||
* Correctly handle HTTP redirects to URLs containing escape characters.
|
||||
* Fix integer overflow in `os.epoch`.
|
||||
* Allow using pickaxes (and other items) for turtle upgrades which have mod-specific NBT.
|
||||
* Fix duplicate turtle/pocket upgrade recipes appearing in JEI.
|
||||
|
||||
# New features in CC: Tweaked 1.94.0
|
||||
|
||||
* Add getter for window visibility (devomaa)
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
clear clears the screen.
|
||||
clear clears the screen and/or resets the palette.
|
||||
ex:
|
||||
"clear" clears the screen, but keeps the palette.
|
||||
"clear screen" does the same as "clear"
|
||||
"clear palette" resets the palette, but doesn't clear the screen
|
||||
"clear all" clears the screen and resets the palette
|
||||
|
||||
@@ -1,13 +1,23 @@
|
||||
New features in CC: Tweaked 1.94.0
|
||||
New features in CC: Tweaked 1.95.0
|
||||
|
||||
* Add getter for window visibility (devomaa)
|
||||
* Generic peripherals are no longer experimental, and on by default.
|
||||
* Use term.blit to draw boxes in paintutils (Lemmmy).
|
||||
* Optimise the paint program's initial render.
|
||||
* Several documentation improvments (Gibbo3771, MCJack123).
|
||||
* `fs.combine` now accepts multiple arguments.
|
||||
* Add a setting (`bios.strict_globals`) to error when accidentally declaring a global. (Lupus590).
|
||||
* Add an improved help viewer which allows scrolling up and down (MCJack123).
|
||||
* Add `cc.strings` module, with utilities for wrapping text (Lupus590).
|
||||
* The `clear` program now allows resetting the palette too (Luca0208).
|
||||
|
||||
And several bug fixes:
|
||||
* Fix turtles not getting advancements when turtles are on.
|
||||
* Draw in-hand pocket computers with the correct transparent flags enabled.
|
||||
* Several bug fixes to SNBT parsing.
|
||||
* Fix several programs using their original name instead of aliases in usage hints (Lupus590).
|
||||
* Fix memory leak in generic peripherals.
|
||||
* Fix crash when a turtle is broken while being ticked.
|
||||
* `textutils.*tabulate` now accepts strings _or_ numbers.
|
||||
* We now deny _all_ local IPs, using the magic `$private` host. Previously the IPv6 loopback interface was not blocked.
|
||||
* Fix crash when rendering monitors if the block has not yet been synced. You will need to regenerate the config file to apply this change.
|
||||
* `read` now supports numpad enter (TheWireLord)
|
||||
* Correctly handle HTTP redirects to URLs containing escape characters.
|
||||
* Fix integer overflow in `os.epoch`.
|
||||
* Allow using pickaxes (and other items) for turtle upgrades which have mod-specific NBT.
|
||||
* Fix duplicate turtle/pocket upgrade recipes appearing in JEI.
|
||||
|
||||
Type "help changelog" to see the full version history.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
--- A collection of helper methods for working with input completion, such
|
||||
-- as that require by @{read}.
|
||||
-- as that require by @{_G.read}.
|
||||
--
|
||||
-- @module cc.completion
|
||||
-- @see cc.shell.completion For additional helpers to use with
|
||||
@@ -29,10 +29,11 @@ end
|
||||
-- @tparam { string... } choices The list of choices to complete from.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed item.
|
||||
-- @treturn { string... } A list of suffixes of matching strings.
|
||||
-- @usage Call @{read}, completing the names of various animals.
|
||||
-- @usage Call @{_G.read}, completing the names of various animals.
|
||||
--
|
||||
-- local completion = require "cc.completion"
|
||||
-- local animals = { "dog", "cat", "lion", "unicorn" }
|
||||
-- read(nil, nil, function(text) return choice(text, animals) end)
|
||||
-- read(nil, nil, function(text) return completion.choice(text, animals) end)
|
||||
local function choice(text, choices, add_space)
|
||||
expect(1, text, "string")
|
||||
expect(2, choices, "table")
|
||||
@@ -45,7 +46,9 @@ end
|
||||
-- @tparam string text The input string to complete.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed name.
|
||||
-- @treturn { string... } A list of suffixes of matching peripherals.
|
||||
-- @usage read(nil, nil, peripheral)
|
||||
-- @usage
|
||||
-- local completion = require "cc.completion"
|
||||
-- read(nil, nil, completion.peripheral)
|
||||
local function peripheral_(text, add_space)
|
||||
expect(1, text, "string")
|
||||
expect(2, add_space, "boolean", "nil")
|
||||
@@ -59,7 +62,9 @@ local sides = redstone.getSides()
|
||||
-- @tparam string text The input string to complete.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed side.
|
||||
-- @treturn { string... } A list of suffixes of matching sides.
|
||||
-- @usage read(nil, nil, side)
|
||||
-- @usage
|
||||
-- local completion = require "cc.completion"
|
||||
-- read(nil, nil, completion.side)
|
||||
local function side(text, add_space)
|
||||
expect(1, text, "string")
|
||||
expect(2, add_space, "boolean", "nil")
|
||||
@@ -71,7 +76,9 @@ end
|
||||
-- @tparam string text The input string to complete.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed settings.
|
||||
-- @treturn { string... } A list of suffixes of matching settings.
|
||||
-- @usage read(nil, nil, setting)
|
||||
-- @usage
|
||||
-- local completion = require "cc.completion"
|
||||
-- read(nil, nil, completion.setting)
|
||||
local function setting(text, add_space)
|
||||
expect(1, text, "string")
|
||||
expect(2, add_space, "boolean", "nil")
|
||||
@@ -85,7 +92,9 @@ local command_list
|
||||
-- @tparam string text The input string to complete.
|
||||
-- @tparam[opt] boolean add_space Whether to add a space after the completed command.
|
||||
-- @treturn { string... } A list of suffixes of matching commands.
|
||||
-- @usage read(nil, nil, command)
|
||||
-- @usage
|
||||
-- local completion = require "cc.completion"
|
||||
-- read(nil, nil, completion.command)
|
||||
local function command(text, add_space)
|
||||
expect(1, text, "string")
|
||||
expect(2, add_space, "boolean", "nil")
|
||||
|
||||
@@ -1,7 +1,26 @@
|
||||
--- The @{cc.expect} library provides helper functions for verifying that
|
||||
-- function arguments are well-formed and of the correct type.
|
||||
--
|
||||
-- @module cc.expect
|
||||
--[[- The @{cc.expect} library provides helper functions for verifying that
|
||||
function arguments are well-formed and of the correct type.
|
||||
|
||||
@module cc.expect
|
||||
@usage Define a basic function and check it has the correct arguments.
|
||||
|
||||
local expect = require "cc.expect"
|
||||
local expect, field = expect.expect, expect.field
|
||||
|
||||
local function add_person(name, info)
|
||||
expect(1, name, "string")
|
||||
expect(2, info, "table", "nil")
|
||||
|
||||
if info then
|
||||
print("Got age=", field(info, "age", "number"))
|
||||
print("Got gender=", field(info, "gender", "string", "nil"))
|
||||
end
|
||||
end
|
||||
|
||||
add_person("Anastazja") -- `info' is optional
|
||||
add_person("Kion", { age = 23 }) -- `gender' is optional
|
||||
add_person("Caoimhin", { age = 23, gender = true }) -- error!
|
||||
]]
|
||||
|
||||
local native_select, native_type = select, type
|
||||
|
||||
@@ -34,7 +53,7 @@ local function expect(index, value, ...)
|
||||
local name
|
||||
if native_type(debug) == "table" and native_type(debug.getinfo) == "function" then
|
||||
local ok, info = pcall(debug.getinfo, 3, "nS")
|
||||
if ok and info.name and #info.name ~= "" and info.what ~= "C" then name = info.name end
|
||||
if ok and info.name and info.name ~= "" and info.what ~= "C" then name = info.name end
|
||||
end
|
||||
|
||||
local type_names = get_type_names(...)
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
-- @module cc.pretty
|
||||
-- @usage Print a table to the terminal
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- pretty.write(pretty.pretty({ 1, 2, 3 }))
|
||||
-- pretty.print(pretty.pretty({ 1, 2, 3 }))
|
||||
--
|
||||
-- @usage Build a custom document and display it
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- pretty.write(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
||||
-- pretty.print(pretty.group(pretty.text("hello") .. pretty.space_line .. pretty.text("world")))
|
||||
|
||||
local expect = require "cc.expect"
|
||||
local expect, field = expect.expect, expect.field
|
||||
@@ -67,6 +67,9 @@ end
|
||||
-- @tparam[opt] number colour The colour this text should be printed with. If not given, we default to the current
|
||||
-- colour.
|
||||
-- @treturn Doc The document with the provided text.
|
||||
-- @usage Write some blue text.
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- pretty.print(pretty.text("Hello!", colours.blue))
|
||||
local function text(text, colour)
|
||||
expect(1, text, "string")
|
||||
expect(2, colour, "number", "nil")
|
||||
@@ -101,8 +104,11 @@ end
|
||||
--
|
||||
-- @tparam Doc|string ... The documents to concatenate.
|
||||
-- @treturn Doc The concatenated documents.
|
||||
-- @usage pretty.concat(doc1, " - ", doc2)
|
||||
-- @usage doc1 .. " - " .. doc2
|
||||
-- @usage
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- local doc1, doc2 = pretty.text("doc1"), pretty.text("doc2")
|
||||
-- print(pretty.concat(doc1, " - ", doc2))
|
||||
-- print(doc1 .. " - " .. doc2) -- Also supports ..
|
||||
local function concat(...)
|
||||
local args = table.pack(...)
|
||||
for i = 1, args.n do
|
||||
@@ -135,7 +141,9 @@ Doc.__concat = concat --- @local
|
||||
-- @tparam number depth The number of spaces with which the document should be indented.
|
||||
-- @tparam Doc doc The document to indent.
|
||||
-- @treturn Doc The nested document.
|
||||
-- @usage pretty.nest(2, pretty.text("foo\nbar"))
|
||||
-- @usage
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- print(pretty.nest(2, pretty.text("foo\nbar")))
|
||||
local function nest(depth, doc)
|
||||
expect(1, depth, "number")
|
||||
if getmetatable(doc) ~= Doc then expect(2, doc, "document") end
|
||||
@@ -169,6 +177,12 @@ end
|
||||
--
|
||||
-- @tparam Doc doc The document to group.
|
||||
-- @treturn Doc The grouped document.
|
||||
-- @usage Uses group to show things being displayed on one or multiple lines.
|
||||
--
|
||||
-- local pretty = require "cc.pretty"
|
||||
-- local doc = pretty.group("Hello" .. pretty.space_line .. "World")
|
||||
-- print(pretty.render(doc, 5)) -- On multiple lines
|
||||
-- print(pretty.render(doc, 20)) -- Collapsed onto one.
|
||||
local function group(doc)
|
||||
if getmetatable(doc) ~= Doc then expect(1, doc, "document") end
|
||||
|
||||
|
||||
@@ -9,9 +9,13 @@
|
||||
-- @usage Construct the package and require function, and insert them into a
|
||||
-- custom environment.
|
||||
--
|
||||
-- local env = setmetatable({}, { __index = _ENV })
|
||||
-- local r = require "cc.require"
|
||||
-- local env = setmetatable({}, { __index = _ENV })
|
||||
-- env.require, env.package = r.make(env, "/")
|
||||
--
|
||||
-- -- Now we have our own require function, separate to the original.
|
||||
-- local r2 = env.require "cc.require"
|
||||
-- print(r, r2)
|
||||
|
||||
local expect = require and require("cc.expect") or dofile("rom/modules/main/cc/expect.lua")
|
||||
local expect = expect.expect
|
||||
|
||||
@@ -1,15 +1,28 @@
|
||||
--- A collection of helper methods for working with shell completion.
|
||||
--
|
||||
-- Most programs may be completed using the @{build} helper method, rather than
|
||||
-- manually switching on the argument index.
|
||||
--
|
||||
-- Note, the helper functions within this module do not accept an argument index,
|
||||
-- and so are not directly usable with the @{shell.setCompletionFunction}. Instead,
|
||||
-- wrap them using @{build}, or your own custom function.
|
||||
--
|
||||
-- @module cc.shell.completion
|
||||
-- @see cc.completion For more general helpers, suitable for use with @{read}.
|
||||
-- @see shell.setCompletionFunction
|
||||
--[[- A collection of helper methods for working with shell completion.
|
||||
|
||||
Most programs may be completed using the @{build} helper method, rather than
|
||||
manually switching on the argument index.
|
||||
|
||||
Note, the helper functions within this module do not accept an argument index,
|
||||
and so are not directly usable with the @{shell.setCompletionFunction}. Instead,
|
||||
wrap them using @{build}, or your own custom function.
|
||||
|
||||
@module cc.shell.completion
|
||||
@see cc.completion For more general helpers, suitable for use with @{_G.read}.
|
||||
@see shell.setCompletionFunction
|
||||
|
||||
@usage Register a completion handler for example.lua which prompts for a
|
||||
choice of options, followed by a directory, and then multiple files.
|
||||
|
||||
local completion = require "cc.shell.completion"
|
||||
local complete = completion.build(
|
||||
{ completion.choice, { "get", "put" } },
|
||||
completion.dir,
|
||||
{ completion.file, many = true }
|
||||
)
|
||||
shell.setCompletionFunction("example.lua", complete)
|
||||
read(nil, nil, shell.complete, "example ")
|
||||
]]
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
local completion = require "cc.completion"
|
||||
@@ -69,37 +82,29 @@ local function program(shell, text)
|
||||
return shell.completeProgram(text)
|
||||
end
|
||||
|
||||
--- A helper function for building shell completion arguments.
|
||||
--
|
||||
-- This accepts a series of single-argument completion functions, and combines
|
||||
-- them into a function suitable for use with @{shell.setCompletionFunction}.
|
||||
--
|
||||
-- @tparam nil|table|function ... Every argument to @{build} represents an argument
|
||||
-- to the program you wish to complete. Each argument can be one of three types:
|
||||
--
|
||||
-- - `nil`: This argument will not be completed.
|
||||
--
|
||||
-- - A function: This argument will be completed with the given function. It is
|
||||
-- called with the @{shell} object, the string to complete and the arguments
|
||||
-- before this one.
|
||||
--
|
||||
-- - A table: This acts as a more powerful version of the function case. The table
|
||||
-- must have a function as the first item - this will be called with the shell,
|
||||
-- string and preceding arguments as above, but also followed by any additional
|
||||
-- items in the table. This provides a more convenient interface to pass
|
||||
-- options to your completion functions.
|
||||
--
|
||||
-- If this table is the last argument, it may also set the `many` key to true,
|
||||
-- which states this function should be used to complete any remaining arguments.
|
||||
--
|
||||
-- @usage Prompt for a choice of options, followed by a directory, and then multiple
|
||||
-- files.
|
||||
--
|
||||
-- complete.build(
|
||||
-- { complete.choice, { "get", "put" } },
|
||||
-- complete.dir,
|
||||
-- { complete.file, many = true }
|
||||
-- )
|
||||
--[[- A helper function for building shell completion arguments.
|
||||
|
||||
This accepts a series of single-argument completion functions, and combines
|
||||
them into a function suitable for use with @{shell.setCompletionFunction}.
|
||||
|
||||
@tparam nil|table|function ... Every argument to @{build} represents an argument
|
||||
to the program you wish to complete. Each argument can be one of three types:
|
||||
|
||||
- `nil`: This argument will not be completed.
|
||||
|
||||
- A function: This argument will be completed with the given function. It is
|
||||
called with the @{shell} object, the string to complete and the arguments
|
||||
before this one.
|
||||
|
||||
- A table: This acts as a more powerful version of the function case. The table
|
||||
must have a function as the first item - this will be called with the shell,
|
||||
string and preceding arguments as above, but also followed by any additional
|
||||
items in the table. This provides a more convenient interface to pass
|
||||
options to your completion functions.
|
||||
|
||||
If this table is the last argument, it may also set the `many` key to true,
|
||||
which states this function should be used to complete any remaining arguments.
|
||||
]]
|
||||
local function build(...)
|
||||
local arguments = table.pack(...)
|
||||
for i = 1, arguments.n do
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
--- Various utilities for working with strings and text.
|
||||
--
|
||||
-- @see textutils For additional string related utilities.
|
||||
|
||||
local expect = require "cc.expect".expect
|
||||
|
||||
--- Wraps a block of text, so that each line fits within the given width.
|
||||
--
|
||||
-- This may be useful if you want to wrap text before displaying it to a
|
||||
-- @{monitor} or @{printer} without using @{_G.print|print}.
|
||||
--
|
||||
-- @tparam string text The string to wrap.
|
||||
-- @tparam[opt] number width The width to constrain to, defaults to the width of
|
||||
-- the terminal.
|
||||
--
|
||||
-- @treturn { string... } The wrapped input string.
|
||||
-- @usage require "cc.strings".wrap("This is a long piece of text", 10)
|
||||
local function wrap(text, width)
|
||||
expect(1, text, "string")
|
||||
expect(2, width, "number", "nil")
|
||||
width = width or term.getSize()
|
||||
|
||||
|
||||
local lines, lines_n, current_line = {}, 0, ""
|
||||
local function push_line()
|
||||
lines_n = lines_n + 1
|
||||
lines[lines_n] = current_line
|
||||
current_line = ""
|
||||
end
|
||||
|
||||
local pos, length = 1, #text
|
||||
local sub, match = string.sub, string.match
|
||||
while pos <= length do
|
||||
local head = sub(text, pos, pos)
|
||||
if head == " " or head == "\t" then
|
||||
local whitespace = match(text, "^[ \t]+", pos)
|
||||
current_line = current_line .. whitespace
|
||||
pos = pos + #whitespace
|
||||
elseif head == "\n" then
|
||||
push_line()
|
||||
pos = pos + 1
|
||||
else
|
||||
local word = match(text, "^[^ \t\n]+", pos)
|
||||
pos = pos + #word
|
||||
if #word > width then
|
||||
-- Print a multiline word
|
||||
while #word > 0 do
|
||||
local space_remaining = width - #current_line - 1
|
||||
if space_remaining <= 0 then
|
||||
push_line()
|
||||
space_remaining = width
|
||||
end
|
||||
|
||||
current_line = current_line .. sub(word, 1, space_remaining)
|
||||
word = sub(word, space_remaining + 1)
|
||||
end
|
||||
else
|
||||
-- Print a word normally
|
||||
if width - #current_line < #word then push_line() end
|
||||
current_line = current_line .. word
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
push_line()
|
||||
|
||||
-- Trim whitespace longer than width.
|
||||
for k, line in pairs(lines) do
|
||||
line = line:sub(1, width)
|
||||
lines[k] = line
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
--- Makes the input string a fixed width. This either truncates it, or pads it
|
||||
-- with spaces.
|
||||
--
|
||||
-- @tparam string line The string to normalise.
|
||||
-- @tparam[opt] number width The width to constrain to, defaults to the width of
|
||||
-- the terminal.
|
||||
--
|
||||
-- @treturn string The string with a specific width.
|
||||
-- @usage require "cc.strings".ensure_width("a short string", 20)
|
||||
-- @usage require "cc.strings".ensure_width("a rather long string which is truncated", 20)
|
||||
local function ensure_width(line, width)
|
||||
expect(1, line, "string")
|
||||
expect(2, width, "number", "nil")
|
||||
width = width or term.getSize()
|
||||
|
||||
line = line:sub(1, width)
|
||||
if #line < width then
|
||||
line = line .. (" "):rep(width - #line)
|
||||
end
|
||||
|
||||
return line
|
||||
end
|
||||
|
||||
return {
|
||||
wrap = wrap,
|
||||
ensure_width = ensure_width,
|
||||
}
|
||||
@@ -1,2 +1,33 @@
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
local tArgs = { ... }
|
||||
|
||||
local function printUsage()
|
||||
local programName = arg[0] or fs.getName(shell.getRunningProgram())
|
||||
print("Usages:")
|
||||
print(programName)
|
||||
print(programName .. " screen")
|
||||
print(programName .. " palette")
|
||||
print(programName .. " all")
|
||||
end
|
||||
|
||||
local function clear()
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
end
|
||||
|
||||
local function resetPalette()
|
||||
for i = 0, 15 do
|
||||
term.setPaletteColour(math.pow(2, i), term.nativePaletteColour(math.pow(2, i)))
|
||||
end
|
||||
end
|
||||
|
||||
local sCommand = tArgs[1] or "screen"
|
||||
if sCommand == "screen" then
|
||||
clear()
|
||||
elseif sCommand == "palette" then
|
||||
resetPalette()
|
||||
elseif sCommand == "all" then
|
||||
clear()
|
||||
resetPalette()
|
||||
else
|
||||
printUsage()
|
||||
end
|
||||
|
||||
@@ -233,14 +233,32 @@ local function drawCanvasPixel(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
local color_hex_lookup = {}
|
||||
for i = 0, 15 do
|
||||
color_hex_lookup[2 ^ i] = string.format("%x", i)
|
||||
end
|
||||
|
||||
--[[
|
||||
Converts each colour in a single line of the canvas and draws it
|
||||
returns: nil
|
||||
]]
|
||||
local function drawCanvasLine(y)
|
||||
local text, fg, bg = "", "", ""
|
||||
for x = 1, w - 2 do
|
||||
drawCanvasPixel(x, y)
|
||||
local pixel = getCanvasPixel(x, y)
|
||||
if pixel then
|
||||
text = text .. " "
|
||||
fg = fg .. "0"
|
||||
bg = bg .. color_hex_lookup[pixel or canvasColour]
|
||||
else
|
||||
text = text .. "\127"
|
||||
fg = fg .. color_hex_lookup[colours.grey]
|
||||
bg = bg .. color_hex_lookup[canvasColour]
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(1, y)
|
||||
term.blit(text, fg, bg)
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
@@ -13,14 +13,119 @@ if sTopic == "index" then
|
||||
return
|
||||
end
|
||||
|
||||
local strings = require "cc.strings"
|
||||
local function word_wrap(text, width)
|
||||
local lines = strings.wrap(text, width)
|
||||
|
||||
-- Normalise the strings suitable for use with blit. We could skip this and
|
||||
-- just use term.write, but saves us a clearLine call.
|
||||
for k, line in pairs(lines) do
|
||||
lines[k] = strings.ensure_width(line, width)
|
||||
end
|
||||
|
||||
return lines
|
||||
end
|
||||
|
||||
local sFile = help.lookup(sTopic)
|
||||
local file = sFile ~= nil and io.open(sFile) or nil
|
||||
if file then
|
||||
local sContents = file:read("*a")
|
||||
file:close()
|
||||
|
||||
local _, nHeight = term.getSize()
|
||||
textutils.pagedPrint(sContents, nHeight - 3)
|
||||
else
|
||||
print("No help available")
|
||||
if not file then
|
||||
printError("No help available")
|
||||
return
|
||||
end
|
||||
|
||||
local contents = file:read("*a"):gsub("(\n *)[-*]( +)", "%1\7%2")
|
||||
file:close()
|
||||
|
||||
local width, height = term.getSize()
|
||||
local lines = word_wrap(contents, width)
|
||||
local print_height = #lines
|
||||
|
||||
-- If we fit within the screen, just display without pagination.
|
||||
if print_height <= height then
|
||||
print(contents)
|
||||
return
|
||||
end
|
||||
|
||||
local offset = 0
|
||||
|
||||
local function draw()
|
||||
local fg, bg = ("0"):rep(width), ("f"):rep(width)
|
||||
for y = 1, height - 1 do
|
||||
term.setCursorPos(1, y)
|
||||
if y + offset > print_height then
|
||||
-- Should only happen if we resize the terminal to a larger one
|
||||
-- than actually needed for the current text.
|
||||
term.clearLine()
|
||||
else
|
||||
term.blit(lines[y + offset], fg, bg)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function draw_menu()
|
||||
term.setTextColor(colors.yellow)
|
||||
term.setCursorPos(1, height)
|
||||
term.clearLine()
|
||||
|
||||
local tag = "Help: " .. sTopic
|
||||
term.write("Help: " .. sTopic)
|
||||
|
||||
if width >= #tag + 16 then
|
||||
term.setCursorPos(width - 14, height)
|
||||
term.write("Press Q to exit")
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
draw_menu()
|
||||
|
||||
while true do
|
||||
local event, param = os.pullEvent()
|
||||
if event == "key" then
|
||||
if param == keys.up and offset > 0 then
|
||||
offset = offset - 1
|
||||
draw()
|
||||
elseif param == keys.down and offset < print_height - height then
|
||||
offset = offset + 1
|
||||
draw()
|
||||
elseif param == keys.pageUp and offset > 0 then
|
||||
offset = math.max(offset - height + 2, 0)
|
||||
draw()
|
||||
elseif param == keys.pageDown and offset < print_height - height then
|
||||
offset = math.min(offset + height - 2, print_height - height)
|
||||
draw()
|
||||
elseif param == keys.home then
|
||||
offset = 0
|
||||
draw()
|
||||
elseif param == keys["end"] then
|
||||
offset = print_height - height
|
||||
draw()
|
||||
elseif param == keys.q then
|
||||
sleep(0) -- Super janky, but consumes stray "char" events.
|
||||
break
|
||||
end
|
||||
elseif event == "mouse_scroll" then
|
||||
if param < 0 and offset > 0 then
|
||||
offset = offset - 1
|
||||
draw()
|
||||
elseif param > 0 and offset < print_height - height then
|
||||
offset = offset + 1
|
||||
draw()
|
||||
end
|
||||
elseif event == "term_resize" then
|
||||
local new_width, new_height = term.getSize()
|
||||
|
||||
if new_width ~= width then
|
||||
lines = word_wrap(contents, new_width)
|
||||
print_height = #lines
|
||||
end
|
||||
|
||||
width, height = new_width, new_height
|
||||
offset = math.max(math.min(offset, print_height - height), 0)
|
||||
draw()
|
||||
draw_menu()
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(1, 1)
|
||||
term.clear()
|
||||
|
||||
@@ -383,7 +383,7 @@ end
|
||||
--
|
||||
-- @tparam string sLine The input to complete.
|
||||
-- @treturn { string }|nil The list of possible completions.
|
||||
-- @see read For more information about completion.
|
||||
-- @see _G.read For more information about completion.
|
||||
-- @see shell.completeProgram
|
||||
-- @see shell.setCompletionFunction
|
||||
-- @see shell.getCompletionInfo
|
||||
@@ -461,7 +461,7 @@ end
|
||||
-- The completion function.
|
||||
-- @see cc.shell.completion Various utilities to help with writing completion functions.
|
||||
-- @see shell.complete
|
||||
-- @see read For more information about completion.
|
||||
-- @see _G.read For more information about completion.
|
||||
function shell.setCompletionFunction(program, complete)
|
||||
expect(1, program, "string")
|
||||
expect(2, complete, "function")
|
||||
|
||||
@@ -49,6 +49,7 @@ end
|
||||
|
||||
shell.setCompletionFunction("rom/programs/alias.lua", completion.build(nil, completion.program))
|
||||
shell.setCompletionFunction("rom/programs/cd.lua", completion.build(completion.dir))
|
||||
shell.setCompletionFunction("rom/programs/clear.lua", completion.build({ completion.choice, { "screen", "palette", "all" } }))
|
||||
shell.setCompletionFunction("rom/programs/copy.lua", completion.build(
|
||||
{ completion.dirOrFile, true },
|
||||
completion.dirOrFile
|
||||
|
||||
Reference in New Issue
Block a user