docs: add README

This commit is contained in:
LordMZTE 2023-06-08 16:38:03 +02:00
parent cf233fd3c6
commit 82b21f7161
Signed by: LordMZTE
GPG key ID: B64802DC33A64FF6

137
README.md Normal file
View file

@ -0,0 +1,137 @@
# znvim
Zig bindings for Neovim's internal C functions. The ABI follows Neovim's master branch!
## Usage
1. Add the dependency to your project's `build.zig.zon`:
```zig
.{
.name = "my-config",
.version = "0.0.0",
.dependencies = .{
.znvim = .{
.url = "https://mzte.de/git/LordMZTE/znvim/archive/<latest commit hash>.tar.gz",
.hash = "<paste hash here; leave this field out when pasting the URL>",
},
},
}
```
2. Structure your `build.zig` something like this:
```zig
const std = @import("std");
pub fn build(b: *std.build.Builder) !void {
const target = b.standardTargetOptions(.{});
if (target.os_tag orelse @import("builtin").os.tag == .windows)
// windows is an error in many ways
return error.Windows;
const mode = b.standardOptimizeOption(.{});
// Build your config as a dynamically linked library.
const lib = b.addSharedLibrary(.{
.name = "my-config",
.root_source_file = .{ .path = "src/main.zig" },
.target = target,
.optimize = mode,
});
// Declare the znvim dependency here.
const znvim_dep = b.dependency("znvim", .{ .target = target, .optimize = mode });
// Add both the nvim_c and znvim modules. You can import these independantly.
lib.addModule("nvim", znvim_dep.module("nvim_c"));
lib.addModule("znvim", znvim_dep.module("znvim"));
// Link libc.
lib.linkLibC();
// LuaJIT is required in order to create a native Lua module neovim can load as well as
// for your Lua API.
lib.linkSystemLibrary("luajit");
// IMPORTANT: without this, lua errors inside your module will cause nvim to SIGABRT!
lib.unwind_tables = true;
// Set the output path to be something sensical.
b.getInstallStep().dependOn(&b.addInstallFile(lib.getOutputSource(), "share/nvim/mzte-nv.so").step);
b.installArtifact(lib);
}
```
3. In your `main.zig`, you want a function called `luaopen_my_config` (where `my_config` is your module name)
This function is loaded by neovim's LuaJIT runtime via `dlsym` and called as an entry point on each `require` of your module.
```zig
const znvim = @import("znvim");
// cImport LuaJIT
const c = @cImport({
@cInclude("lua.h");
@cInclude("lualib.h");
@cInclude("lauxlib.h");
});
pub const std_options = struct {
// You may want to override logFn here in order to redirect std.log log messages to, for example
// nvim notifications. Not doing so will clutter the GUI on log messages.
};
var is_initialized = false;
export fn luaopen_my_config(l: ?*c.lua_State) c_int {
// Make sure we only run initiailzation code once.
// I also recommend putting this into a seperate function you call from Lua once, but that's
// outside the scope of this quick guide.
if (!is_initialized) {
is_initialized = true;
// For example, you could set an option:
// See docs of types inside the znvim module.
znvim.OptionValue.of(true).setLog("number", .both) catch {};
}
c.lua_newtable(l); // create a new lua table to return from `require`
// ... add stuff to that table here
return 1; // 1 indicates one value returned from the lua function
}
```
4. Build your config to `~/.local`
```bash
zig build \
-Doptimize=ReleaseFast \ # Use ReleaseSafe for easier to debug segfaults :D
-p ~/.local # The output path you set in build.zig will be appended to this.
```
5. In Lua, add the path to your shared object to `package.cpath`:
```lua
package.cpath = package.cpath .. ";" .. vim.loop.os_homedir() .. "/.loca/share/nvim/my-config.so"
-- You can now require("my_config")!
```
## WTF???
The whole point of this is so I (and you too!) can write your neovim config in Zig, without going
through the Lua API (or the rather bulky `nvim_*` API functions).
The way this works is by compiling your config's Zig part to a native Lua module, which is then
loaded using just a few lines of Lua code. Here, you can also create a Lua API to call into.
## Structure
znvim is split into 2 modules: `nvim_c` and `znvim`. The former is a `translate-c`'d file of all
of neovim's headers while the latter contains a (work in progress) Zig API for them.
## Development
Apart from writing the Zig API, we need to keep `nvim_c.zig` updated. This file contains the raw C
bindings. It's generated by `generate_bindings.sh`.