Awesome
atom-autocomplete-lua
WARNING! Unmaintained project! Use at your own risk! I don't have the time and motivations to maintain this project anymore. If somebody wants to pick up maintenance for this, please contact me.
Atom Autocomplete+ provider for Lua.
This package aims to parse Lua files with oxyc/luaparse and generate scope and type-aware completions with syntactic analysis.
Features
- Limited type inference mechanism
- Scope-aware variable name suggestions
- Table member completions on
.
and:
- Snippets for function call arguments
- Aware of
setmetatable()
and function return types - Completion for the Lua standard library
.luacompleterc
file to define additional globals- Doc-strings in
.luacompleterc
- Configuration service for other packages to programmatically define globals
- Autocomplete
require
d modules
Available Providers
- Defold IDE - Adds hot reloading, autocompletion and in-line API docs for the Defold game engine.
- LÖVE Atom - Smart autocompletion for the LÖVE framework in Atom.
Configuration
Besides what you can configure in Atom preferences, atom-autocomplete-lua
looks for a .luacompleterc
file in the parent directories of the current file.
If you need to define additional global symbols for your specific Lua environment,
place a .luacompleterc
file in your project root. It's a JSON file with roughly
the following structure:
{
"global": {
"type": "table",
"fields": {
"my_global_var": { /* type definition */ },
/* ... */
}
},
"namedTypes": {
"my_named_type": { /* type definition */ },
/* ... */
}
"luaVersion": "5.2",
"packagePath": "./?.lua",
"cwd": "path/to/lua/module/root"
}
All options are optional. Here's what each option does:
Option | Default | Description |
---|---|---|
global | { type: 'table', fields: {} } | The type definition of the global environment. Define additional fields on this table to declare globals available in your Lua environment. Read the Type definitions section for more info. |
namedTypes | {} | To avoid deep nesting and allow multiple places to reference a single type, you can define named types. Read the Named types section for more info. |
luaVersion | "5.2" | The version of Lua your code is targeting. Valid values are "5.1" , "5.2" , "5.3" , "5.4" and "luajit-2.0" . |
packagePath | "./?.lua" | The value of LUA_PATH used when resolving required modules. |
cwd | . | The current directory used to resolve relative paths in packagePath . If cwd is relative, it's considered relative to the parent directory of .luacompleterc . |
Type definitions
The general format of a type definition is:
{
"type": "type_name", // one of "function", "table", "number", "boolean", "string" or "unknown", "ref"
"description": "Optional short Markdown description of your symbol",
"descriptionPlain": "Optional short plain text description of your symbol (if you don't want Markdown for some reason)",
"link": "http://optional.link/to/full/api/docs"
}
Tables
Tables ("type": "table"
) have 2 more properties:
fields
: Required. An object mapping table fields to their corresponding type definition. Even though Lua allows indexing tables with any value, only string keys are supported for autocompletion purposes.metatable
: Optional. The type definition of the metatable of this table, if it has one.autocomplete-lua
is aware of keys like__index
in this metatable and uses them for completion. If present, thetype
of the metatable must be"table"
.
Example:
{ // Type definition for a student
"type": "table",
"fields": {
"name": { "type": "string" },
"surname": { "type": "string" },
"height": { "type": "number" }
},
"metatable": {
"type": "table",
"fields": {
"__index": {
"type": "table",
"fields": { "skip_rope": { "type": "function" } }
}
}
}
}
Functions
Functions ("type": "function"
) can have a few more optional properties:
returnTypes
: An array of type definitions describing the types of the function's return values.args
: An array of argument name definitions (see below).argsDisplay
: In case you want your arguments to be displayed in the autocomplete dropdown in a custom way, you can provide a string of the argument list here.argsDisplayOmitSelf
: Same as above, but displayed when completing method calls with:
. You should provide the same arg list string, but with the first argument removed. Defaults toargsDisplay
.argTypes
: An array of argument type definitions (ornull
when type is unknown).
Argument names are of the form { "name": "arg_name", "displayName": "display_name" }
,
where displayName
is optional.
displayName
will be displayed in the
autocomplete dropdown, while name
will be part of the inserted snippet.
This is useful for things like optional arguments:
{
"type": "function",
"args": [{ "name": "arg1" }, { "name": "arg2", "displayName": "[arg2]" }],
}
will produce f(arg1, [arg2])
in the dropdown and f(arg1, arg2)
after being inserted.
In rare cases, displayName
might be unsuitable for you. argsDisplay
and argsDisplayOmitSelf
can be used to manually specify the comma-separated list of
arguments.
For example, you can use it to customize comma placement in relation to [
:
{
"type": "function",
"args": [{ "name": "self" }, { "name": "arg1" }, { "name": "arg2" }],
"argsDisplay": "self[, arg1[, arg2]]",
"argsDisplayOmitSelf": "[arg1[, arg2]]"
}
This will produce f(self[, arg1[, arg2]])
in the dropdown and f(self, arg1, arg2)
after being inserted.
Function variants
Sometimes, you may have polymorphic functions which can be called with a number of different argument configurations. You might want to show all of these versions separately in the autocomplete dropdown.
You can provide multiple versions of the same function by moving link
,
description
, args
, argsDisplay
and argsDisplayOmitSelf
inside a
variants
array like so:
{ // Type definition for a get(url_or_filename) function
"type": "function",
"variants": [{
"args": [{ "name": "url" }],
"description": "Fetches an URL and returns a string with the contents"
}, {
"args": [{ "name": "filename" }],
"description": "Read the file at filename and returns a string with the contents"
}]
}
The autocomplete dropdown will show both get(url)
and get(filename)
with their
corresponding descriptions.
Named types
There are often cases where you want to use the same type definition in
multiple places. In these situations, you can use named types in your .luacompleterc
.
Just use { "type": "ref", "name": "my_named_type" }
instead of your type
definition and define my_named_type
in namedTypes
.
Example .luacompleterc:
{
"global": {
"type": "table",
"fields": {
"make_a_cat": {
"type": "function",
"returnTypes": [{ "type": "ref", "name": "cat" }]
},
"make_a_cat_somehow_else": {
"type": "function",
"returnTypes": [{ "type": "ref", "name": "cat" }]
}
}
},
"namedTypes": {
"cat": {
"type": "table",
"fields": {
"color": { "type": "string" },
"is_fluffy": { "type": "boolean" }
}
}
}
}
Option providers
All the options provided in a .luacompleterc
can be programmatically provided
by plugin packages (like Defold IDE).
Start by adding this to your package.json
:
"providedServices": {
"autocomplete-lua.options-provider": {
"versions": {
"1.0.0": "getOptionProvider"
}
}
}
Then, in your package's JS object:
getOptionProvider () {
return myProvider; // You can also return an array of providers if you have more
}
The provider is an object (or a class) with the following interface:
const myProvider = {
priority: 20,
getOptions (request, getPreviousOptions, utils, cache) {
// Just return the options from the previous provider
return getPreviousOptions().then(previousOptions => {
return { options: previousOptions }
})
}
dispose () {
// Destroy stuff
}
}
priority
and getPreviousOptions()
Each time a completion is needed (roughly at each keystroke), autocomplete-lua
sorts all the option providers by their priority and calls the getOptions()
method of the highest priority option provider.
The option provider can choose to call the next-highest-in-priority provider
by calling getPreviousOptions()
. getPreviousOptions()
returns a promise
to the options object provided by the next-in-line provider.
There are 3 option providers that come with autocomplete-lua
:
- StdLibProvider. Priority 100. Adds Lua's standard library functions to the options.
- LuaCompleteRcProvider. Priority 10. Adds the contents of
.luacompleterc
to the options. - EmptyProvider. Priority 0. Just returns an empty options object. Acts as fallback for
getPreviousOptions()
.
dispose()
Optional function. dispose()
is called when your provider is not needed anymore.
getOptions(request, getPreviousOptions, utils, cache)
This function is called when your provider is expected to return a new set of options.
request
comes directly from Autocomplete+,
with the addition of request.filePath
, the absolute path to the current file.
The return value is an object of the form { options }
. The same object is passed
to getOptions()
as cache
the next time the function is called on the same file,
so you can store additional arbitrary properties on it that you'd like to receive
in cache
. Returning a promise to this object is also supported.
It's strongly encouraged to always return the same options
object if nothing
changed from the last call. Read on about utils.mergeOptionsCached()
for
a simple way to do this.
utils.reviveOptions(options)
Takes an options object and resolves all references to named types. (Replaces { type: 'ref', name: 'myRef' }
with namedTypes.myRef
). This should be called after you read the
options object from permanent storage.
Returns the same options
object.
utils.mergeOptions(previousOptions, newOptions)
Takes 2 options objects, merges them and returns the result.
Fields in newOptions
overwrite fields in previousOptions
. The global
fields are deeply merged.
utils.mergeOptionsCached(previousOptions, newOptions, cache[, merger])
Uses mergeOptions()
to merge previousOptions
and newOptions
if any of the
two are different from cache.previousOptions
and cache.newOptions
, else
returns cache.options
.
If the merge takes place, merger(mergedOptions, previousOptions, newOptions)
is called on the newly merged object to do additional custom merging work.
Returns an object { options, previousOptions, newOptions }
suitable for returning
as the cache object from getOptions()
.
A recommended pattern is the following:
getOptions = async (request, getPreviousOptions, utils, cache) => {
if (providerIsNotApplicableToTheCurrentFile) {
return { options: await getPreviousOptions() }
}
const newOptions = conjureABunchOfNewOptions()
const previousOptions = await getPreviousOptions()
return utils.mergeOptionsCached(previousOptions, newOptions, cache, mergedOptions => {
mergedOptions.oneMoreThing = 'this thing'
})
}
util.<typename>New()
Creates a new type definition for a <typename>
. Available functions are:
tableNew()
, booleanNew()
, functionNew()
, numberNew()
, unknownNew()
, nilNew()
util.tableSet(table, key, value)
Sets the field identified by key
in the table type definition table
to the
type definition value
.
util.tableGet(table, key)
Gets the type definition corresponding to the field identified by key
in the
table type definition table
.
util.tableSetMetatable(table, metatable)
Sets the metatable type definition in the table type definition table
to the
type definition metatable
.
util.tableGetMetatable(table)
Gets the type definition of the metatable of the table type definition table
.