Editor Setup
Manifests and specs are Lua, so any editor with a lua-language-server client gives you completion, hover documentation, and diagnostics on envy's API. envy ships the type definitions and writes the configuration that points the server at them.
What envy sets up
envy init creates .luarc.json next to the
manifest:
$ envy init . bin
Created bin/envy
Created ./envy.lua
Created ./.luarc.json
Updated ./.gitignore
Initialized envy project.
{
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
"runtime.version": "Lua 5.4",
"workspace.library": [
".envy/cache/envy/0.3.0",
"~/Library/Caches/envy/envy/0.3.0",
"~/.cache/envy/envy/0.3.0",
"${env:USERPROFILE}/AppData/Local/envy/envy/0.3.0"
],
"diagnostics.globals": [
"envy", "IDENTITY", "PACKAGES", "DEPENDENCIES", "PRODUCTS",
"FETCH", "STAGE", "BUILD", "INSTALL", "SETUP", "ENVY_IMPORTER"
],
"completion.enable": true
}
Four library paths: the project-local cache tree
first, then one per platform's default cache location, with
${env:USERPROFILE}/AppData/Local/envy covering Windows. It is a union rather
than a choice, because .luarc.json is committed while the cache root is
per-user state: the same manifest is local for whoever ran envy cache --local
and shared for everyone else. Only one path exists on any given machine and the
language server ignores the rest, which is why this file can be committed and
shared. If your project sets @envy cache-local, that path replaces the default
.envy/cache entry, relative rather than absolute so the file names no machine.
${env:VAR} is the language server's own placeholder syntax, so it is expanded
by the server rather than by a shell, and forward slashes are correct on Windows
too. Each path points at envy/<version> in the cache, where envy extracts
envy.lua, a few hundred lines of
LuaCATS annotations covering
envy.run, envy.path, envy.commit_fetch, the phase globals, and the rest of
the API.
Commit .luarc.json. It is machine-independent and version-matched to the envy
the project pins.
Keeping it current
The library paths name an exact envy version, so they go stale when the project
moves. sync and
deploy fix them:
$ envy use 0.3.0
$ envy sync
Updated .luarc.json types paths
The rewrite removes any workspace.library entry that ends in envy/<semver>
and appends the current four. Everything else in the file is left alone, so your
own settings and library paths survive:
{
"workspace.library": [
"/my/other/lua/lib",
".envy/cache/envy/0.3.0",
"~/Library/Caches/envy/envy/0.3.0",
"~/.cache/envy/envy/0.3.0",
"${env:USERPROFILE}/AppData/Local/envy/envy/0.3.0"
],
"custom.setting": "preserved"
}
Two opt-outs, both by omission:
- Delete
.luarc.jsonand envy stops creating or touching it.syncanddeployonly update a file that already exists. - Remove the
workspace.librarykey and the rewrite skips the file entirely.
init will not overwrite an existing .luarc.json either. It prints the paths
instead:
$ envy init . bin
.luarc.json already exists at ./.luarc.json
To enable envy autocompletion, add the following to workspace.library:
".envy/cache/envy/0.3.0"
"~/Library/Caches/envy/envy/0.3.0"
"~/.cache/envy/envy/0.3.0"
"${env:USERPROFILE}/AppData/Local/envy/envy/0.3.0"
It prints the same four paths it would have written, so pasting them in gets you the same result.
Globals
diagnostics.globals is what stops the language server from reporting
undefined-global on the names envy assigns meaning to:
| Global | Where |
|---|---|
envy | everywhere, the API table |
IDENTITY, DEPENDENCIES, PRODUCTS, PLATFORMS | specs |
FETCH, STAGE, BUILD, INSTALL, SETUP | specs, the phase verbs |
OPTIONS, USER_MANAGED, EXPORTABLE, VENDOR, DISPLAY | specs |
PACKAGES, DEFAULT_SHELL, PACKAGE_DEPOTS, VENDOR_ROOT | manifests |
ENVY_IMPORTER | an imported manifest, set by envy.import |
ENVY_BUNDLE | a module loaded out of a bundle, from envy 0.4.7. See ENVY_BUNDLE. |
ENVY_SHELL | both, the shell constants |
The list init writes covers the common ones. Add what your project uses, for
example BUNDLES in a manifest with a bundle, or BUNDLE and SPECS in a
bundle repo:
"diagnostics.globals": [
"envy", "IDENTITY", "PACKAGES", "BUNDLES", "DEPENDENCIES", "PRODUCTS",
"FETCH", "STAGE", "BUILD", "INSTALL", "SETUP", "ENVY_IMPORTER",
"ENVY_BUNDLE"
]
Nothing breaks without them. The names are still resolved at run time by envy, and the only cost is a warning squiggle.
Per editor
The language server reads .luarc.json from the workspace root, so open the
directory holding the manifest.
- VS Code: install the
Lua extension.
It picks up
.luarc.jsonwith no further configuration. - Neovim: enable
lua_ls, throughnvim-lspconfigorvim.lsp.configon 0.11 and later. It finds.luarc.jsonby root marker. - Zed: Lua support is built in and uses the same server.
- Anything else: run
lua-language-serverover the workspace. The configuration is in the file, not in the editor.
In a monorepo, each manifest directory gets its own
.luarc.json from init, but the language server only reads the one at the
workspace root. Open a component directory directly when editing its specs, or
keep the root file authoritative and let the others be redundant.
See also
envy init- Lua API for the same API in prose
- Writing a Spec