Merge branch 'mc-1.14.x' into mc-1.15.x

This commit is contained in:
SquidDev 2020-04-23 10:04:37 +01:00
commit 33260a7747
15 changed files with 494 additions and 155 deletions

View File

@ -1,4 +1,4 @@
# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](http://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
# ![CC: Tweaked](logo.png) [![Download CC: Tweaked on CurseForge](https://cf.way2muchnoise.eu/title/cc-tweaked.svg)](https://minecraft.curseforge.com/projects/cc-tweaked "Download CC: Tweaked on CurseForge")
CC: Tweaked is a fork of [ComputerCraft], adding programmable computers, turtles and more to Minecraft.

View File

@ -23,7 +23,7 @@ body {
"Droid Sans", "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
}
code, pre, .parameter, .type, .definition-name, .reference {
code, pre, .parameter, .type, .definition-name, .reference-code {
font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
}

View File

@ -1,5 +1,5 @@
# Mod properties
mod_version=1.86.2
mod_version=1.87.0
# Minecraft properties (update mods.toml when changing)
mc_version=1.15.2

View File

@ -2,10 +2,11 @@
(sources
/doc/stub/
/src/main/resources/data/computercraft/lua/bios.lua
/src/main/resources/data/computercraft/lua/rom/
/src/main/resources/*/computercraft/lua/bios.lua
/src/main/resources/*/computercraft/lua/rom/
/src/test/resources/test-rom)
(doc
(title "CC: Tweaked")
(index doc/index.md)
@ -14,13 +15,13 @@
(library-path
/doc/stub/
/src/main/resources/data/computercraft/lua/rom/apis
/src/main/resources/data/computercraft/lua/rom/apis/command
/src/main/resources/data/computercraft/lua/rom/apis/turtle
/src/main/resources/*/computercraft/lua/rom/apis
/src/main/resources/*/computercraft/lua/rom/apis/command
/src/main/resources/*/computercraft/lua/rom/apis/turtle
/src/main/resources/data/computercraft/lua/rom/modules/main
/src/main/resources/data/computercraft/lua/rom/modules/command
/src/main/resources/data/computercraft/lua/rom/modules/turtle))
/src/main/resources/*/computercraft/lua/rom/modules/main
/src/main/resources/*/computercraft/lua/rom/modules/command
/src/main/resources/*/computercraft/lua/rom/modules/turtle))
(at /
(linters
@ -34,9 +35,7 @@
;; be good to find a compromise in the future, but this works for now.
-var:unused-arg
;; Suppress a couple of documentation comments warnings for now. We'll
;; hopefully be able to remove them in the future.
-doc:undocumented -doc:undocumented-arg -doc:unresolved-reference
;; Some APIS (keys, colour and os mainly) are incomplete right now.
-var:unresolved-member)
(lint
(bracket-spaces
@ -49,8 +48,8 @@
;; We disable the unused global linter in bios.lua and the APIs. In the future
;; hopefully we'll get illuaminate to handle this.
(at
(/src/main/resources/data/computercraft/lua/bios.lua
/src/main/resources/data/computercraft/lua/rom/apis/)
(/src/main/resources/*/computercraft/lua/bios.lua
/src/main/resources/*/computercraft/lua/rom/apis/)
(linters -var:unused-global)
(lint (allow-toplevel-global true)))
@ -59,19 +58,27 @@
(linters -var:unused-global)
(lint (allow-toplevel-global true)))
;; Ensure any fully documented modules stay fully documented.
;; Suppress warnings for currently undocumented modules.
(at
(/src/main/resources/data/computercraft/lua/rom/apis/colors.lua
/src/main/resources/data/computercraft/lua/rom/apis/colours.lua
/src/main/resources/data/computercraft/lua/rom/apis/disk.lua
/src/main/resources/data/computercraft/lua/rom/apis/gps.lua
/src/main/resources/data/computercraft/lua/rom/apis/help.lua
/src/main/resources/data/computercraft/lua/rom/apis/keys.lua
/src/main/resources/data/computercraft/lua/rom/apis/paintutils.lua
/src/main/resources/data/computercraft/lua/rom/apis/parallel.lua
/src/main/resources/data/computercraft/lua/rom/apis/peripheral.lua
/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua
/src/main/resources/data/computercraft/lua/rom/apis/settings.lua
/src/main/resources/data/computercraft/lua/rom/apis/texutils.lua
/src/main/resources/data/computercraft/lua/rom/apis/vector.lua)
(linters doc:undocumented doc:undocumented-arg))
(/doc/stub/commands.lua
/doc/stub/fs.lua
/doc/stub/http.lua
/doc/stub/os.lua
/doc/stub/redstone.lua
/doc/stub/term.lua
/doc/stub/turtle.lua
/src/main/resources/*/computercraft/lua/rom/apis/command/commands.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/modules/main/cc/shell/completion.lua)
(linters -doc:undocumented -doc:undocumented-arg))
;; These currently rely on unknown references.
(at
(/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/shell/completion.lua
/src/main/resources/*/computercraft/lua/rom/programs/advanced/multishell.lua
/src/main/resources/*/computercraft/lua/rom/programs/shell.lua)
(linters -doc:unresolved-reference))

View File

@ -521,14 +521,11 @@ function os.run(_tEnv, _sPath, ...)
expect(1, _tEnv, "table")
expect(2, _sPath, "string")
local tArgs = table.pack(...)
local tEnv = _tEnv
setmetatable(tEnv, { __index = _G })
local fnFile, err = loadfile(_sPath, nil, tEnv)
if fnFile then
local ok, err = pcall(function()
fnFile(table.unpack(tArgs, 1, tArgs.n))
end)
local ok, err = pcall(fnFile, ...)
if not ok then
if err and err ~= "" then
printError(err)
@ -926,7 +923,7 @@ settings.define("list.show_hidden", {
})
settings.define("motd.enable", {
default = false,
default = pocket == nil,
description = "Display a random message when the computer starts up.",
type = "boolean",
})

View File

@ -106,7 +106,7 @@ end
-- This generally returns the same as @{disk.getLabel} for records.
--
-- @tparam string name The name of the disk drive.
-- @treturn string|false|nil The track title, `false` if there is not a music
-- @treturn string|false|nil The track title, @{false} if there is not a music
-- record in the drive or `nil` if no drive is present.
function getAudioTitle(name)
if isDrive(name) then

View File

@ -32,7 +32,7 @@ for _, v in ipairs(valid_types) do valid_types[v] = true end
-- you to provide defaults and additional metadata.
--
-- @tparam string name The name of this option
-- @tparam[opt] { description? = string, default? = value, type? = string } options
-- @tparam[opt] { description? = string, default? = any, type? = string } options
-- Options for this setting. This table accepts the following fields:
--
-- - `description`: A description which may be printed when running the `set` program.
@ -127,7 +127,7 @@ end
--- Get details about a specific setting.
--
-- @tparam string name The name of the setting to get.
-- @treturn { description? = string, default? = value, type? = string, value? = value }
-- @treturn { description? = string, default? = any, type? = string, value? = any }
-- Information about this setting. This includes all information from @{settings.define},
-- as well as this setting's value.
function getDetails(name)

View File

@ -1,3 +1,33 @@
# New features in CC: Tweaked 1.87.0
* Add documentation to many Lua functions. This is published online at https://tweaked.cc/.
* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module.
* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive.
* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time.
* Update Cobalt version. This backports several features from Lua 5.2 and 5.3:
- The `__len` metamethod may now be used by tables.
- Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes.
- Add `utf8` lib.
- Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace.
- `table.unpack` now uses `__len` and `__index` metamethods.
- Parser errors now include the token where the error occured.
* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT.
* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description.
* Enable the motd on non-pocket computers.
* Allow using the menu with the mouse in edit and paint (JakobDev).
* Add Danish and Korean translations (ChristianLW, mindy15963)
* Fire `mouse_up` events in the monitor program.
* Allow specifying a timeout to `websocket.receive`.
* Increase the maximimum limit for websocket messages.
* Optimise capacity checking of computer/disk folders.
And several bug fixes:
* Fix turtle texture being incorrectly oriented (magiczocker10).
* Prevent copying folders into themselves.
* Normalise file paths within shell.setDir (JakobDev)
* Fix turtles treating waterlogged blocks as water.
* Register an entity renderer for the turtle's fake player.
# New features in CC: Tweaked 1.86.2
* Fix peripheral.getMethods returning an empty table

View File

@ -1,7 +1,31 @@
New features in CC: Tweaked 1.86.2
New features in CC: Tweaked 1.87.0
* Fix peripheral.getMethods returning an empty table
* Update to Minecraft 1.15.2. This is currently alpha-quality and so is missing
missing features and may be unstable.
* Add documentation to many Lua functions. This is published online at https://tweaked.cc/.
* Replace to pretty-printer in the Lua REPL. It now supports displaying functions and recursive tables. This printer is may be used within your own code through the `cc.pretty` module.
* Add `fs.getCapacity`. A complement to `fs.getFreeSpace`, this returns the capacity of the supplied drive.
* Add `fs.getAttributes`. This provides file size and type, as well as creation and modification time.
* Update Cobalt version. This backports several features from Lua 5.2 and 5.3:
- The `__len` metamethod may now be used by tables.
- Add `\z`, hexadecimal (`\x00`) and unicode (`\u0000`) string escape codes.
- Add `utf8` lib.
- Mirror Lua's behaviour of tail calls more closely. Native functions are no longer tail called, and tail calls are displayed in the stack trace.
- `table.unpack` now uses `__len` and `__index` metamethods.
- Parser errors now include the token where the error occured.
* Add `textutils.unserializeJSON`. This can be used to decode standard JSON and stringified-NBT.
* The `settings` API now allows "defining" settings. This allows settings to specify a default value and description.
* Enable the motd on non-pocket computers.
* Allow using the menu with the mouse in edit and paint (JakobDev).
* Add Danish and Korean translations (ChristianLW, mindy15963)
* Fire `mouse_up` events in the monitor program.
* Allow specifying a timeout to `websocket.receive`.
* Increase the maximimum limit for websocket messages.
* Optimise capacity checking of computer/disk folders.
And several bug fixes:
* Fix turtle texture being incorrectly oriented (magiczocker10).
* Prevent copying folders into themselves.
* Normalise file paths within shell.setDir (JakobDev)
* Fix turtles treating waterlogged blocks as water.
* Register an entity renderer for the turtle's fake player.
Type "help changelog" to see the full version history.

View File

@ -16,7 +16,7 @@ local completion = require "cc.completion"
--- Complete the name of a file relative to the current working directory.
--
-- @tparam shell shell The shell we're completing in
-- @tparam table shell The shell we're completing in
-- @tparam { string... } choices The list of choices to complete from.
-- @treturn { string... } A list of suffixes of matching files.
local function file(shell, text)
@ -25,7 +25,7 @@ end
--- Complete the name of a directory relative to the current working directory.
--
-- @tparam shell shell The shell we're completing in
-- @tparam table shell The shell we're completing in
-- @tparam { string... } choices The list of choices to complete from.
-- @treturn { string... } A list of suffixes of matching directories.
local function dir(shell, text)
@ -35,7 +35,7 @@ end
--- Complete the name of a file or directory relative to the current working
-- directory.
--
-- @tparam shell shell The shell we're completing in
-- @tparam table shell The shell we're completing in
-- @tparam { string... } choices The list of choices to complete from.
-- @tparam { string... } previous The shell arguments before this one.
-- @tparam[opt] boolean add_space Whether to add a space after the completed item.
@ -61,9 +61,10 @@ end
--- Complete the name of a program.
--
-- @tparam shell shell The shell we're completing in
-- @tparam table shell The shell we're completing in
-- @tparam { string... } choices The list of choices to complete from.
-- @treturn { string... } A list of suffixes of matching programs.
-- @see shell.completeProgram
local function program(shell, text)
return shell.completeProgram(text)
end

View File

@ -1,43 +1,23 @@
View the source code at https://github.com/SquidDev-CC/CC-Tweaked
Please report bugs at https://github.com/SquidDev-CC/CC-Tweaked. Thanks!
View the documentation at https://wiki.computercraft.cc
Visit the forum at https://forums.computercraft.cc
Show off your programs or ask for help at our forum: https://forums.computercraft.cc
You can disable these messages by running "set motd.enable false".
You can create directories with "mkdir".
Want to see hidden files? Run "set list.show_hidden true".
Run "list" or "ls" to see all files in a directory.
You can delete files and directories with "delete" or "rm".
Use "pastebin put" to upload a program to pastebin.
Use "pastebin get" to download a program from pastebin.
Use "pastebin run" to run a program from pastebin.
Use the "edit" program to create and edit your programs.
You can copy files with "copy" or "cp".
You can use "wget run <url>" to run a program from the internet.
You can use "wget" to download a file from the internet.
On an advanced computer you can use "fg" or "bg" to run multiple programs at the same time.
Use "type" to see if a path is a file or a directory.
Get a list of all programs with "programs".
Use an advanced computer to use colours and the mouse.
With a speaker you can play sounds.
Use "motd" to print the Message of the Day.
You can disable the startup from a computer with "set shell.allow_startup false".
You can disable the startup from a disk with "set shell.allow_disk_startup false".
Programs that are placed in the "startup" folder in the root of a computer are started on boot.
Use a modem to connect with other computers.
With the "gps" program you can get the position of a computer.
Use "monitor" to run a program on a attached monitor.
View all attached peripherals with "peripherals".
Use "time" to see the in-game time.
You can set the label of a computer with "label set".
A computer needs a label to keep its files if it is destroyed.
You can disable auto completion in the shell with "set shell.autocomplete false".
You can disable auto completion in edit with "set edit.autocomplete false".
Don't forget to label your computer with "label set".
Feeling creative? Use a printer to print a book!
Files beginning with a "." character are hidden from "list" by default.
Files beginning with a "." are hidden from "list" by default.
Running "set" lists the current values of all settings.
Some programs are only available on advanced computers, turtles, pocket computers, or command computers.
The "equip" and "unequip" programs let you add or remove supported upgrades from a turtle or pocket computer without crafting.
You can change the color of a disk by crafting it with dye.
Right-clicking a turtle with a dye changes its color.
Some programs are only available on advanced computers, turtles, pocket computers or command computers.
The "equip" programs let you add upgrades to a turtle without crafting.
You can change the color of a disk by crafting or right clicking it with dye.
You can print on a printed page again to get multiple colors.
Holding the Control and T keys terminates the running program.
Holding Control and S or R shuts down or reboots the computer you are using.
Holding the Ctrl and T keys terminates the running program.

View File

@ -1,3 +1,21 @@
--- Multishell allows multiple programs to be run at the same time.
--
-- When multiple programs are running, it displays a tab bar at the top of the
-- screen, which allows you to switch between programs. New programs can be
-- launched using the `fg` or `bg` programs, or using the @{shell.openTab} and
-- @{multishell.launch} functions.
--
-- Each process is identified by its ID, which corresponds to its position in
-- the tab list. As tabs may be opened and closed, this ID is _not_ constant
-- over a program's run. As such, be careful not to use stale IDs.
--
-- As with @{shell}, @{multishell} is not a "true" API. Instead, it is a
-- standard program, which launches a shell and injects its API into the shell's
-- environment. This API is not available in the global environment, and so is
-- not available to @{os.loadAPI|APIs}.
--
-- @module[module] multishell
local expect = dofile("rom/modules/main/cc/expect.lua").expect
-- Setup process switching
@ -190,12 +208,26 @@ local function setMenuVisible(bVis)
end
end
local multishell = {}
local multishell = {} --- @export
--- Get the currently visible process. This will be the one selected on
-- the tab bar.
--
-- Note, this is different to @{getCurrent}, which returns the process which is
-- currently executing.
--
-- @treturn number The currently visible process's index.
-- @see setFocus
function multishell.getFocus()
return nCurrentProcess
end
--- Change the currently visible process.
--
-- @tparam number n The process index to switch to.
-- @treturn boolean If the process was changed successfully. This will
-- return @{false} if there is no process with this id.
-- @see getFocus
function multishell.setFocus(n)
expect(1, n, "number")
if n >= 1 and n <= #tProcesses then
@ -206,6 +238,13 @@ function multishell.setFocus(n)
return false
end
--- Get the title of the given tab.
--
-- This starts as the name of the program, but may be changed using
-- @{multishell.setTitle}.
-- @tparam number n The process index.
-- @treturn string|nil The current process title, or @{nil} if the
-- process doesn't exist.
function multishell.getTitle(n)
expect(1, n, "number")
if n >= 1 and n <= #tProcesses then
@ -214,19 +253,45 @@ function multishell.getTitle(n)
return nil
end
function multishell.setTitle(n, sTitle)
--- Set the title of the given process.
--
-- @tparam number n The process index.
-- @tparam string title The new process title.
-- @see getTitle
-- @usage Change the title of the current process
--
-- multishell.setTitle(multishell.getCurrent(), "Hello")
function multishell.setTitle(n, title)
expect(1, n, "number")
expect(2, sTitle, "string")
expect(2, title, "string")
if n >= 1 and n <= #tProcesses then
setProcessTitle(n, sTitle)
setProcessTitle(n, title)
redrawMenu()
end
end
--- Get the index of the currently running process.
--
-- @treturn number The currently running process.
function multishell.getCurrent()
return nRunningProcess
end
--- Start a new process, with the given environment, program and arguments.
--
-- The returned process index is not constant over the program's run. It can be
-- safely used immediately after launching (for instance, to update the title or
-- switch to that tab). However, after your program has yielded, it may no
-- longer be correct.
--
-- @tparam table tProgramEnv The environment to load the path under.
-- @tparam string sProgramPath The path to the program to run.
-- @param ... Additional arguments to pass to the program.
-- @treturn number The index of the created process.
-- @see os.run
-- @usage Run the "hello" program, and set its title to "Hello!"
-- local id = multishell.launch({}, "/rom/programs/fun/hello.lua")
-- multishell.setTitle(id, "Hello!")
function multishell.launch(tProgramEnv, sProgramPath, ...)
expect(1, tProgramEnv, "table")
expect(2, sProgramPath, "string")
@ -238,6 +303,9 @@ function multishell.launch(tProgramEnv, sProgramPath, ...)
return nResult
end
--- Get the number of processes within this multishell.
--
-- @treturn number The number of processes.
function multishell.getCount()
return #tProcesses
end

View File

@ -15,7 +15,7 @@ end
-- Create .lua files by default
if not fs.exists(sPath) and not string.find(sPath, "%.") then
local sExtension = settings.get("edit.default_extension", "")
local sExtension = settings.get("edit.default_extension")
if sExtension ~= "" and type(sExtension) == "string" then
sPath = sPath .. "." .. sExtension
end
@ -61,7 +61,12 @@ if peripheral.find("printer") then
end
table.insert(tMenuItems, "Exit")
local sStatus = "Press Ctrl to access menu"
local sStatus
if term.isColour() then
sStatus = "Press Ctrl or click here to access menu"
else
sStatus = "Press Ctrl to access menu"
end
if #sStatus > w - 5 then
sStatus = "Press Ctrl for menu"
end
@ -725,16 +730,35 @@ while bRunning do
end
elseif sEvent == "mouse_click" then
local cx, cy = param2, param3
if not bMenu then
if param == 1 then
-- Left click
local cx, cy = param2, param3
if cy < h then
local newY = math.min(math.max(scrollY + cy, 1), #tLines)
local newX = math.min(math.max(scrollX + cx, 1), #tLines[newY] + 1)
setCursor(newX, newY)
else
bMenu = true
redrawMenu()
end
end
else
if cy == h then
local nMenuPosEnd = 1
local nMenuPosStart = 1
for n, sMenuItem in ipairs(tMenuItems) do
nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1
if cx > nMenuPosStart and cx < nMenuPosEnd then
doMenuItem(n)
end
nMenuPosEnd = nMenuPosEnd + 1
nMenuPosStart = nMenuPosEnd
end
else
bMenu = false
redrawMenu()
end
end
elseif sEvent == "mouse_scroll" then

View File

@ -19,7 +19,7 @@ local canvas = {}
local mChoices = { "Save", "Exit" }
-- The message displayed in the footer bar
local fMessage = "Press Ctrl to access menu"
local fMessage = "Press Ctrl or click here to access menu"
-------------------------
-- Initialisation --
@ -46,7 +46,7 @@ end
-- Create .nfp files by default
if not fs.exists(sPath) and not string.find(sPath, "%.") then
local sExtension = settings.get("paint.default_extension", "")
local sExtension = settings.get("paint.default_extension")
if sExtension ~= "" and type(sExtension) == "string" then
sPath = sPath .. "." .. sExtension
end
@ -252,6 +252,29 @@ local function drawCanvas()
end
end
local menu_choices = {
Save = function()
if bReadOnly then
fMessage = "Access denied"
return false
end
local success, err = save(sPath)
if success then
fMessage = "Saved to " .. sPath
else
if err then
fMessage = "Error saving to " .. err
else
fMessage = "Error saving to " .. sPath
end
end
return false
end,
Exit = function()
return true
end,
}
--[[
Draws menu options and handles input from within the menu.
returns: true if the program is to be exited; false otherwise
@ -261,6 +284,7 @@ local function accessMenu()
local selection = 1
term.setBackgroundColour(colours.black)
while true do
-- Draw the menu
term.setCursorPos(1, h)
@ -269,27 +293,28 @@ local function accessMenu()
for k, v in pairs(mChoices) do
if selection == k then
term.setTextColour(colours.yellow)
local ox = term.getCursorPos()
term.write("[" .. string.rep(" ", #v) .. "]")
term.setCursorPos(ox + 1, h)
term.write("[")
term.setTextColour(colours.white)
term.write(v)
term.setCursorPos(term.getCursorPos() + 1, h)
term.setTextColour(colours.yellow)
term.write("]")
term.setTextColour(colours.white)
else
term.write(" " .. v .. " ")
end
end
-- Handle input in the menu
local id, key = os.pullEvent("key")
local id, param1, param2, param3 = os.pullEvent()
if id == "key" then
-- S and E are shortcuts
if key == keys.s then
selection = 1
key = keys.enter
elseif key == keys.e then
selection = 2
key = keys.enter
local key = param1
-- Handle menu shortcuts.
for _, menu_item in ipairs(mChoices) do
local k = keys[menu_item:sub(1, 1):lower()]
if k and k == key then
return menu_choices[menu_item]()
end
end
if key == keys.right then
@ -308,29 +333,25 @@ local function accessMenu()
elseif key == keys.enter then
-- Select an option
if mChoices[selection] == "Save" then
if bReadOnly then
fMessage = "Access denied"
return false
end
local success, err = save(sPath)
if success then
fMessage = "Saved to " .. sPath
else
if err then
fMessage = "Error saving to " .. err
else
fMessage = "Error saving to " .. sPath
end
end
return false
elseif mChoices[selection] == "Exit" then
return true
end
return menu_choices[mChoices[selection]]()
elseif key == keys.leftCtrl or keys == keys.rightCtrl then
-- Cancel the menu
return false
end
elseif id == "mouse_click" then
local cx, cy = param2, param3
if cy ~= h then return false end -- Exit the menu
local nMenuPosEnd = 1
local nMenuPosStart = 1
for _, sMenuItem in ipairs(mChoices) do
nMenuPosEnd = nMenuPosEnd + #sMenuItem + 1
if cx > nMenuPosStart and cx < nMenuPosEnd then
return menu_choices[sMenuItem]()
end
nMenuPosEnd = nMenuPosEnd + 1
nMenuPosStart = nMenuPosEnd
end
end
end
end
@ -378,6 +399,10 @@ local function handleEvents()
canvas[p3][p2] = paintColour
drawCanvasPixel(p2, p3)
elseif p3 == h and id == "mouse_click" then
-- Open menu
programActive = not accessMenu()
drawInterface()
end
elseif id == "key" then
if p1 == keys.leftCtrl or p1 == keys.rightCtrl then

View File

@ -1,3 +1,15 @@
--- The shell API provides access to CraftOS's command line interface.
--
-- It allows you to @{run|start programs}, @{setCompletionFunction|add
-- completion for a program}, and much more.
--
-- @{shell} is not a "true" API. Instead, it is a standard program, which its
-- API into the programs that it launches. This allows for multiple shells to
-- run at the same time, but means that the API is not available in the global
-- environment, and so is unavailable to other @{os.loadAPI|APIs}.
--
-- @module[module] shell
local expect = dofile("rom/modules/main/cc/expect.lua").expect
local multishell = multishell
@ -15,7 +27,7 @@ local tAliases = parentShell and parentShell.aliases() or {}
local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {}
local tProgramStack = {}
local shell = {}
local shell = {} --- @export
local function createShellEnv(sDir)
local tEnv = {}
tEnv.shell = shell
@ -172,6 +184,18 @@ local function tokenise(...)
end
-- Install shell API
--- Run a program with the supplied arguments.
--
-- All arguments are concatenated together and then parsed as a command line. As
-- a result, `shell.run("program a b")` is the same as `shell.run("program",
-- "a", "b")`.
--
-- @tparam string ... The program to run and its arguments.
-- @treturn boolean Whether the program exited successfully.
-- @usage Run `paint my-image` from within your program:
--
-- shell.run("paint", "my-image")
function shell.run(...)
local tWords = tokenise(...)
local sCommand = tWords[1]
@ -181,38 +205,83 @@ function shell.run(...)
return false
end
--- Exit the current shell.
--
-- This does _not_ terminate your program, it simply makes the shell terminate
-- after your program has finished. If this is the toplevel shell, then the
-- computer will be shutdown.
function shell.exit()
bExit = true
end
--- Return the current working directory. This is what is displayed before the
-- `> ` of the shell prompt, and is used by @{shell.resolve} to handle relative
-- paths.
--
-- @treturn string The current working directory.
-- @see setDir To change the working directory.
function shell.dir()
return sDir
end
function shell.setDir(_sDir)
expect(1, _sDir, "string")
if not fs.isDir(_sDir) then
--- Set the current working directory.
--
-- @tparam string dir The new working directory.
-- @throws If the path does not exist or is not a directory.
-- @usage Set the working directory to "rom"
--
-- shell.setDir("rom")
function shell.setDir(dir)
expect(1, dir, "string")
if not fs.isDir(dir) then
error("Not a directory", 2)
end
sDir = fs.combine(_sDir, "")
sDir = fs.combine(dir, "")
end
--- Set the path where programs are located.
--
-- The path is composed of a list of directory names in a string, each separated
-- by a colon (`:`). On normal turtles will look in the current directory (`.`),
-- `/rom/programs` and `/rom/programs/turtle` folder, making the path
-- `.:/rom/programs:/rom/programs/turtle`.
--
-- @treturn string The current shell's path.
-- @see setPath To change the current path.
function shell.path()
return sPath
end
function shell.setPath(_sPath)
expect(1, _sPath, "string")
sPath = _sPath
--- Set the @{path|current program path}.
--
-- Be careful to prefix directories with a `/`. Otherwise they will be searched
-- for from the @{shell.dir|current directory}, rather than the computer's root.
--
-- @tparam string path The new program path.
function shell.setPath(path)
expect(1, path, "string")
sPath = path
end
function shell.resolve(_sPath)
expect(1, _sPath, "string")
local sStartChar = string.sub(_sPath, 1, 1)
--- Resolve a relative path to an absolute path.
--
-- The @{fs} and @{io} APIs work using absolute paths, and so we must convert
-- any paths relative to the @{dir|current directory} to absolute ones. This
-- does nothing when the path starts with `/`.
--
-- @tparam string path The path to resolve.
-- @usage Resolve `startup.lua` when in the `rom` folder.
--
-- shell.setDir("rom")
-- print(shell.resolve("startup.lua"))
-- -- => rom/startup.lua
function shell.resolve(path)
expect(1, path, "string")
local sStartChar = string.sub(path, 1, 1)
if sStartChar == "/" or sStartChar == "\\" then
return fs.combine("", _sPath)
return fs.combine("", path)
else
return fs.combine(sDir, _sPath)
return fs.combine(sDir, path)
end
end
@ -226,16 +295,25 @@ local function pathWithExtension(_sPath, _sExt)
return _sPath .. "." .. _sExt
end
function shell.resolveProgram(_sCommand)
expect(1, _sCommand, "string")
--- Resolve a program, using the @{path|program path} and list of @{aliases|aliases}.
--
-- @tparam string command The name of the program
-- @treturn string|nil The absolute path to the program, or @{nil} if it could
-- not be found.
-- @usage Locate the `hello` program.
--
-- shell.resolveProgram("hello")
-- -- => rom/programs/fun/hello.lua
function shell.resolveProgram(command)
expect(1, command, "string")
-- Substitute aliases firsts
if tAliases[_sCommand] ~= nil then
_sCommand = tAliases[_sCommand]
if tAliases[command] ~= nil then
command = tAliases[command]
end
-- If the path is a global path, use it directly
if _sCommand:find("/") or _sCommand:find("\\") then
local sPath = shell.resolve(_sCommand)
if command:find("/") or command:find("\\") then
local sPath = shell.resolve(command)
if fs.exists(sPath) and not fs.isDir(sPath) then
return sPath
else
@ -249,7 +327,7 @@ function shell.resolveProgram(_sCommand)
-- Otherwise, look on the path variable
for sPath in string.gmatch(sPath, "[^:]+") do
sPath = fs.combine(shell.resolve(sPath), _sCommand)
sPath = fs.combine(shell.resolve(sPath), command)
if fs.exists(sPath) and not fs.isDir(sPath) then
return sPath
else
@ -264,7 +342,15 @@ function shell.resolveProgram(_sCommand)
return nil
end
function shell.programs(_bIncludeHidden)
--- Return a list of all programs on the @{shell.path|path}.
--
-- @tparam[opt] boolean include_hidden Include hidden files. Namely, any which
-- start with `.`.
-- @treturn { string } A list of available programs.
-- @usage textutils.tabulate(shell.programs())
function shell.programs(include_hidden)
expect(1, include_hidden, "boolean", "nil")
local tItems = {}
-- Add programs from the path
@ -275,7 +361,7 @@ function shell.programs(_bIncludeHidden)
for n = 1, #tList do
local sFile = tList[n]
if not fs.isDir(fs.combine(sPath, sFile)) and
(_bIncludeHidden or string.sub(sFile, 1, 1) ~= ".") then
(include_hidden or string.sub(sFile, 1, 1) ~= ".") then
if #sFile > 4 and sFile:sub(-4) == ".lua" then
sFile = sFile:sub(1, -5)
end
@ -351,6 +437,21 @@ local function completeProgramArgument(sProgram, nArgument, sPart, tPreviousPart
return nil
end
--- Complete a shell command line.
--
-- This accepts an incomplete command, and completes the program name or
-- arguments. For instance, `l` will be completed to `ls`, and `ls ro` will be
-- completed to `ls rom/`.
--
-- Completion handlers for your program may be registered with
-- @{shell.setCompletionFunction}.
--
-- @tparam string sLine The input to complete.
-- @treturn { string }|nil The list of possible completions.
-- @see read For more information about completion.
-- @see shell.completeProgram
-- @see shell.setCompletionFunction
-- @see shell.getCompletionInfo
function shell.complete(sLine)
expect(1, sLine, "string")
if #sLine > 0 then
@ -388,23 +489,66 @@ function shell.complete(sLine)
return nil
end
function shell.completeProgram(sProgram)
expect(1, sProgram, "string")
return completeProgram(sProgram)
--- Complete the name of a program.
--
-- @tparam string program The name of a program to complete.
-- @treturn { string } A list of possible completions.
-- @see cc.shell.completion.program
function shell.completeProgram(program)
expect(1, program, "string")
return completeProgram(program)
end
function shell.setCompletionFunction(sProgram, fnComplete)
expect(1, sProgram, "string")
expect(2, fnComplete, "function")
tCompletionInfo[sProgram] = {
fnComplete = fnComplete,
--- Set the completion function for a program. When the program is entered on
-- the command line, this program will be called to provide auto-complete
-- information.
--
-- The completion function accepts four arguments:
--
-- 1. The current shell. As completion functions are inherited, this is not
-- guaranteed to be the shell you registered this function in.
-- 2. The index of the argument currently being completed.
-- 3. The current argument. This may be the empty string.
-- 4. A list of the previous arguments.
--
-- For instance, when completing `pastebin put rom/st` our pastebin completion
-- function will receive the shell API, an index of 2, `rom/st` as the current
-- argument, and a "previous" table of `{ "put" }`. This function may then wish
-- to return a table containing `artup.lua`, indicating the entire command
-- should be completed to `pastebin put rom/startup.lua`.
--
-- You completion entries may also be followed by a space, if you wish to
-- indicate another argument is expected.
--
-- @tparam string program The path to the program. This should be an absolute path
-- _without_ the leading `/`.
-- @tparam function(shell: table, index: number, argument: string, previous: { string }):({ string }|nil) complete
-- 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.
function shell.setCompletionFunction(program, complete)
expect(1, program, "string")
expect(2, complete, "function")
tCompletionInfo[program] = {
fnComplete = complete,
}
end
--- Get a table containing all completion functions.
--
-- This should only be needed when building custom shells. Use
-- @{setCompletionFunction} to add a completion function.
--
-- @treturn { [string] = { fnComplete = function } } A table mapping the
-- absolute path of programs, to their completion functions.
function shell.getCompletionInfo()
return tCompletionInfo
end
--- Returns the path to the currently running program.
--
-- @treturn string The absolute path to the running program.
function shell.getRunningProgram()
if #tProgramStack > 0 then
return tProgramStack[#tProgramStack]
@ -412,17 +556,38 @@ function shell.getRunningProgram()
return nil
end
function shell.setAlias(_sCommand, _sProgram)
expect(1, _sCommand, "string")
expect(2, _sProgram, "string")
tAliases[_sCommand] = _sProgram
--- Add an alias for a program.
--
-- @tparam string command The name of the alias to add.
-- @tparam string program The name or path to the program.
-- @usage Alias `vim` to the `edit` program
--
-- shell.setAlias("vim", "edit")
function shell.setAlias(command, program)
expect(1, command, "string")
expect(2, program, "string")
tAliases[command] = program
end
function shell.clearAlias(_sCommand)
expect(1, _sCommand, "string")
tAliases[_sCommand] = nil
--- Remove an alias.
--
-- @tparam string command The alias name to remove.
function shell.clearAlias(command)
expect(1, command, "string")
tAliases[command] = nil
end
--- Get the current aliases for this shell.
--
-- Aliases are used to allow multiple commands to refer to a single program. For
-- instance, the `list` program is aliased `dir` or `ls`. Running `ls`, `dir` or
-- `list` in the shell will all run the `list` program.
--
-- @treturn { [string] = string } A table, where the keys are the names of
-- aliases, and the values are the path to the program.
-- @see shell.setAlias
-- @see shell.resolveProgram This uses aliases when resolving a program name to
-- an absolute path.
function shell.aliases()
-- Copy aliases
local tCopy = {}
@ -433,6 +598,20 @@ function shell.aliases()
end
if multishell then
--- Open a new @{multishell} tab running a command.
--
-- This behaves similarly to @{shell.run}, but instead returns the process
-- index.
--
-- This function is only available if the @{multishell} API is.
--
-- @tparam string ... The command line to run.
-- @see shell.run
-- @see multishell.launch
-- @usage Launch the Lua interpreter and switch to it.
--
-- local id = shell.openTab("lua")
-- shell.switchTab(id)
function shell.openTab(...)
local tWords = tokenise(...)
local sCommand = tWords[1]
@ -448,9 +627,13 @@ if multishell then
end
end
function shell.switchTab(nID)
expect(1, nID, "number")
multishell.setFocus(nID)
--- Switch to the @{multishell} tab with the given index.
--
-- @tparam number id The tab to switch to.
-- @see multishell.setFocus
function shell.switchTab(id)
expect(1, id, "number")
multishell.setFocus(id)
end
end