158 lines
5.9 KiB
Lua
158 lines
5.9 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
|
|
|
|
@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"
|
|
|
|
--- 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.
|
|
]]
|
|
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,
|
|
}
|