1
0
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:
Jonathan Coates
2020-12-25 16:43:32 +00:00
202 changed files with 4269 additions and 2237 deletions

View File

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

View File

@@ -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)

View File

@@ -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")

View File

@@ -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 = {

View File

@@ -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]

View File

@@ -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")

View File

@@ -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)

View File

@@ -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")

View File

@@ -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")

View File

@@ -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)

View File

@@ -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

View File

@@ -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.

View File

@@ -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")

View File

@@ -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(...)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,
}

View File

@@ -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

View File

@@ -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
--[[

View File

@@ -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()

View File

@@ -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")

View File

@@ -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