Suggest-require is a tiny Lua library, for discovering importable modules for Lua's
require function. The intended purpose is as a part of an auto-complete system for Lua written in Lua. The script can, when run as a standalone program, list all of the available modules in the current environment.
The library has been tested with LuaJIT and Lua 5.1 under Linux. Compatibility with Windows, MacOS and other Lua versions is possible, but not assured.
Suggest-require is available as a Lua source file. Usage and examples are available in the source file itself. License is Beerware.
I have been writing a debugging shell in LÖVE for a while now. The shell itself, called Xenoterm, is pretty powerful at this point, with complex interactions and autocompletions, inspired by Fish shell. One of Xenoterm most powerful features is argument auto-completion, where the shell detects which function is being tab-completed on, and suggests several possible arguments. This is similar to when Fish provides suggestions for command-line options, listing files in the local directory, or password files for pass. This allows the user to offload the need to remember specific names or files, and allows them to focus on more important things, like writing code.
Argument completion raison d'être was to make life easier for me and Sketchwhale while working on our games, as we had a habit of forgetting the ids of items and enemies.
For obvious reasons, argument autocompletion makes most sense for functions with a single string argument, and a limited number of inputs. Giving autocompletions for
string.lower would not make any sense. A prime candidate from Lua's standard library was
require, Lua's module importing functionality, which is why I wrote the suggest-require library written back in 2017.
How is suggest-require implemented?
A curious thing about Lua is that it aims to be POSIX compatible in order to be as portable as possible. This means pretty much no built-in knowledge of filesystems. Instead, Lua stores any information about the file system configuration in the
package global: Directory separators, library locations, and so on. Depending upon which platform your Lua is compiled for the proper values are fitted in, but all of this can be inspected and modified at runtime.
require will update its behaviour based upon the values in the table. So if you wanted to figure out the importable modules, you have all the information you want.
Unfortunately, Lua is very filesystem agnostic, to the point of having no API for looking up files in a directory. The Lua Filesystem Module exists for filesystem lookup, but I don't like dependencies for a simple script. Lua does have the
io.popen function for interacting with the system's shell, and this can be used to query the filesystem. On Unixes, we use the
find program to find files, and its builtin pattern matching allowed a bit of a speedup.
So the entire process is roughly:
- Produce glob patterns, based on information in the global
findto execute those globs, retrieving a list of possible libraries.
- The library paths in the
packagetable may contain multiple wildcards (marked as
?in the path), which, when using
requireis replaced with the requested module. Thus our glob approach finds too many files, and we need to prune some of them, (so
./a/a.lua, but not
- Add the names of the already loaded libraries into the mix; these are easily found by looking in the global
Sugggest-require will thus most likely only work on desktop computers, and other full featured environments. These are also the environments where I could see the script being used; a script deep in a game engine or on an embedded device will probably know exactly which modules to import.