(
neovim-nightly tests are temporarily disabled)
First and foremost I am grateful and full of admiration towards noib3 for creating nvim-oxi, the more that I work on my oximlua fork the more that I understand it to be a bloated abomination disfiguring the minimalistic elegance and beauty of nvim-oxi.
With that said, the core motivation for nvim-oximlua is being enthusiastic about Rust and wanting to use a Rust based editor, but being too attached to NVIM/NeoVIM to switch to Muon or Zed. Consequentially, contrary to nvim-oxi's pragmatic goal of creating a small collection of high-perfomance plugins, nvim-oximlua's delusional and far over the rainbow goal is to RIIR the nvim ecosystem and ultimetally maybe even nvim itself, with that in mind, using the Rust ecosystem as much as possible rather than trying to rewrite it too seems like a fair concession.
- From nvim-oxi:
- Direct Rust bindings to nvim's C API (
vim.api.*) that avoid the overhead and limitations of using RPC channels. - Native Rust types for the API's arguments and return values.
- Binding to
vim.schedule. - Basic
libuvintegration. - A testing framework for running tests inside of a nvim instance.
- Direct Rust bindings to nvim's C API (
- From mlua:
- Robust error and panic propagation across the Rust-Lua boundary.
- Generally an industry standard Rust-Lua API.
- From mlua-extras:
- Tooling for generating
lua-lsdefinition files from Rust types and documentation.
- Tooling for generating
neovim-0-11/neovim-0-12/neovim-nightly: Sets the target nvim release for which to compilenvim-oximlua.- Exactly one of those features should be used, not adding any of them will generate a compile time error, using more than one will resolve to the one corresponding to the newest nvim version.
libuv: Enable basiclibuvintegration.test: Enable the testing framework.- TODO:
test-terminator(enableslibuvandtest). mlua-extras: Enablemlua-extrasre-export.
The following features are re-exports of mlua features that enable
corresponding functionality in nvim-oximlua and/or mlua-extras where
relevant.
NOTE: Since nvim-oximlua is locked to the luajit and module features,
the lua*, vendored, module and send (which is locked to vendored)
features are not re-exported. Also the serde feature is not re-exported
since nvim-oximlua heavily relies on serde and thus it is always enabled.
async: enable async/await support (any executor can be used, eg. tokio or async-std).error-send: makemlua:Error: Send + Sync.macros: enable procedural macros (such aschunk!).- NOTE: This does not currently effect any of the
nvim-oximluamacros.
- NOTE: This does not currently effect any of the
anyhow: enableanyhow::Errorconversion into Lua (enableserror-send).userdata-wrappers: opt intoimpl UserDataforRc<T>/Arc<T>/Rc<RefCell<T>>/Arc<Mutex<T>>whereT: UserData
The first step is to create a new library crate with cargo new --lib {your_plugin} and edit the generated Cargo.toml to include:
[lib]
crate-type = ["cdylib"]
[dependencies]
nvim-oximlua = { git = "https://github.com/c-c-k/nvim-oximlua" }NOTE: nvim-oximlua hasn't been released to crates.io yet so it has to be
installed from it's github source.
NOTE: mlua and mlua-extras should NOT be directly added to avoid
potential version and feature conflicts, please use the nvim-oximlua::mlua
and nvim-oximlua::mlua_extras re-exports instead. All relevant mlua and
mlua-extras features are re-exported as nvim-oximlua features
(see mlua Re-Exports above).
Next, in lib.rs we'll annotate the entry point of the plugin with the
#[mlua::lua_module] macro and add the nvim-oximlua::init shim:
// lib.rs
use nvim_oximlua as nvim;
use nvim::mlua;
#[mlua::lua_module]
fn foo(lua: &mlua::Lua) -> mlua::Result<i32> {
nvim::init(lua)?;
Ok(42)
}macOS users will also need to set a few linker arguments to tell the Rust
linker that the FFI functions nvim-oxi links to will only be available at
runtime. A possible way to do this is to create a .cargo/config file with the
following content:
[target.x86_64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]
[target.aarch64-apple-darwin]
rustflags = [
"-C", "link-arg=-undefined",
"-C", "link-arg=dynamic_lookup",
]After building the crate with cargo build {--release}, cargo will place the
compiled artifacts in target/debug or target/release depending on whether
you built a debug or release version of the crate. If the package name
specified in Cargo.toml is "foo", the library will be named:
libfoo.soon Linux;libfoo.dylibon macOS;foo.dllon Windows.
Next, we need to tell nvim where to load the plugin from. Create a new
directory named lua and place the compiled library inside it, renaming it to
foo.soon Linux;foo.soon macOS;foo.dllon Windows (i.e. no renaming).
Now open nvim and add the parent directory of lua to the
runtimepath, for
example with :set rtp+=~/foobar, assuming lua is in ~/foobar/lua.
And we're done. You can now call the require function to load the plugin just
like any other Lua plugin, which will return the output of the foo() function
defined in lib.rs:
print(require("foo")) -- prints `42`Anything that uses nvim_oxi::lua directly (e.g. implementations of
nvim_oxi::lua:{Pushable, Poppable} for custom types).
If you need this to give nvim-oximlua a try please open an issue with
a request for a compatibility layer for nvim_oxi::lua (preferably with
links to key places in your plugin/config where you need such compatibility).
Until such a request appears adding nvim_oxi::lua compatibility
is low priority.
Hopefully everything else.
Usage of nvim_oximlua::mlua::lua will work but give deprecation warnings.
The cargo dependency needs to changed from nvim-oxi = {...} to
nvim-oximlua = { git = "https://github.com/c-c-k/nvim-oximlua", ... }.
Or nvim-oxi = { package = "nvim-oximlua", git = ... }
To avoid the need to change nvim_oxi to nvim_oximlua everywhere.
Please see the compatibility example, the overall list of changes is:
- The
mluare-export must be in scope (i.e.use nvim_oxi::mlua;). - The entry point macro needs to be changed from
#[nvim_oxi::plugin]to#[mlua::lua_module]. - The entry point function's signature and body need to be adjusted to
#[mlua::lua_module]:- A
lua: &mlua::Luaparameter needs to be added. - The return type needs to be wrapped in
mlua::Result. nvim::init(lua)?;needs to be called at the function body's start.
- A
Please see the examples directory as well as the mlua examples and the mlua-extras examples.
Turning on the test feature enables #[nvim_oxi::test], which replaces the
regular #[test] macro and allows you to test a piece of code from within a
nvim instance using Rust's testing framework.
For example:
use nvim_oximlua::api;
#[nvim_oximlua::test]
fn set_get_del_var() {
api::set_var("foo", 42).unwrap();
assert_eq!(Ok(42), api::get_var("foo"));
assert_eq!(Ok(()), api::del_var("foo"));
}When cargo test is executed, the generated code will spawn a new nvim
process with the nvim binary in your $PATH, test your code, and exit.
There's a gotcha: you can't have two tests with the same name in the same crate, even if they belong to different modules. For example, this won't work:
mod a {
#[nvim_oximlua::test]
fn foo() {}
}
mod b {
#[nvim_oximlua::test]
fn foo() {}
}Note that all integration tests must live inside a separate cdylib crate with
the following build script:
// build.rs
fn main() -> Result<(), nvim_oximlua::tests::BuildError> {
nvim_oximlua::tests::build()
}