CC-Tweaked/src/main/resources/data/computercraft/lua/rom/modules/main/cc/shell/completion.lua

153 lines
5.8 KiB
Lua

--- 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
local expect = require "cc.expect".expect
local completion = require "cc.completion"
--- Complete the name of a file relative to the current working directory.
--
-- @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)
return fs.complete(text, shell.dir(), true, false)
end
--- Complete the name of a directory relative to the current working directory.
--
-- @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)
return fs.complete(text, shell.dir(), false, true)
end
--- Complete the name of a file or directory relative to the current working
-- directory.
--
-- @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.
-- @treturn { string... } A list of suffixes of matching files and directories.
local function dirOrFile(shell, text, previous, add_space)
local results = fs.complete(text, shell.dir(), true, true)
if add_space then
for n = 1, #results do
local result = results[n]
if result:sub(-1) ~= "/" then
results[n] = result .. " "
end
end
end
return results
end
local function wrap(func)
return function(shell, text, previous, ...)
return func(text, ...)
end
end
--- Complete the name of a program.
--
-- @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
--- 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 }
-- )
local function build(...)
local arguments = table.pack(...)
for i = 1, arguments.n do
local arg = arguments[i]
if arg ~= nil then
expect(i, arg, "table", "function")
if type(arg) == "function" then
arg = { arg }
arguments[i] = arg
end
if type(arg[1]) ~= "function" then
error(("Bad table entry #1 at argument #%d (expected function, got %s)"):format(i, type(arg[1])), 2)
end
if arg.many and i < arguments.n then
error(("Unexpected 'many' field on argument #%d (should only occur on the last argument)"):format(i), 2)
end
end
end
return function(shell, index, text, previous)
local arg = arguments[index]
if not arg then
if index <= arguments.n then return end
arg = arguments[arguments.n]
if not arg or not arg.many then return end
end
return arg[1](shell, text, previous, table.unpack(arg, 2))
end
end
return {
file = file,
dir = dir,
dirOrFile = dirOrFile,
program = program,
-- Re-export various other functions
help = wrap(help.completeTopic), --- Wraps @{help.completeTopic} as a @{build} compatible function.
choice = wrap(completion.choice), --- Wraps @{cc.completion.choice} as a @{build} compatible function.
peripheral = wrap(completion.peripheral), --- Wraps @{cc.completion.peripheral} as a @{build} compatible function.
side = wrap(completion.side), --- Wraps @{cc.completion.side} as a @{build} compatible function.
setting = wrap(completion.setting), --- Wraps @{cc.completion.setting} as a @{build} compatible function.
command = wrap(completion.command), --- Wraps @{cc.completion.command} as a @{build} compatible function.
build = build,
}