Skip to content

jinzhongjia/znvim

Repository files navigation

znvim

A lightweight Neovim RPC client for Zig that discovers the runtime API via nvim_get_api_info, manages transports, and ships a high-level MessagePack helper so application code never needs to touch the raw zig-msgpack API.

Highlights

  • Runtime API discovery – obtain structured metadata (ApiInfo, ApiFunction, ApiParameter) describing exactly what the connected Neovim instance exposes.
  • Multiple transports – talk to Neovim over Unix sockets, TCP, stdio pipes, named pipes on Windows, or auto-spawned nvim --embed processes.
  • Allocator-friendly client – the caller keeps ownership of allocations and can decide how long payloads live.
  • MessagePack façadeznvim.msgpack wraps zig-msgpack with ergonomic constructors (msgpack.array, msgpack.object, msgpack.encode, …) plus type-safe readers (msgpack.expectString, msgpack.asArray, …).
  • Examples ready to buildzig build examples produces runnable binaries that demonstrate common workflows.

Requirements

  • Zig 0.15.x
  • A running Neovim instance compiled with --embed support (standard builds already have it)

Installation

Add the package to your project using zig fetch:

zig fetch --save https://github.com/jinzhongjia/znvim/archive/main.tar.gz

Wire the module in build.zig:

const znvim_dep = b.dependency("znvim", .{
    .target = target,
    .optimize = optimize,
});
const znvim = znvim_dep.module("znvim");

exe.root_module.addImport("znvim", znvim);

Quick Start

const std = @import("std");
const znvim = @import("znvim");
const msgpack = znvim.msgpack;

pub fn main() !void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer switch (gpa.deinit()) {
        .ok => {},
        .leak => std.debug.print("warning: leaked allocations\n", .{}),
    };
    const allocator = gpa.allocator();

    const address = std.process.getEnvVarOwned(allocator, "NVIM_LISTEN_ADDRESS") catch {
        std.debug.print("Set NVIM_LISTEN_ADDRESS to your Neovim socket before running.\n", .{});
        return error.MissingAddress;
    };
    defer allocator.free(address);

    var client = try znvim.Client.init(allocator, .{ .socket_path = address });
    defer client.deinit();
    try client.connect();

    // Ask Neovim to evaluate a small expression.
    const expr = try msgpack.string(allocator, "join(['zig', 'nvim'], '-')");
    defer msgpack.free(expr, allocator);

    const params = [_]msgpack.Value{expr};
    const response = try client.request("vim_eval", &params);
    defer msgpack.free(response, allocator);

    if (msgpack.asString(response)) |result| {
        std.debug.print("Neovim answered: {s}\n", .{result});
    }
}

Launch Neovim and point NVIM_LISTEN_ADDRESS at the exposed socket:

nvim --headless --listen /tmp/nvim.sock &
export NVIM_LISTEN_ADDRESS=/tmp/nvim.sock
zig build examples
./zig-out/bin/print_api

Examples

Example Description
print_api.zig Connects and prints the first few discovered API functions.
run_command.zig Issues an nvim_command notification that writes to :messages.
eval_expression.zig Evaluates a Vimscript expression and inspects the returned payload.
buffer_lines.zig Reads the current buffer, replaces its content, then verifies the change.
api_lookup.zig Looks up metadata for a single API function by name.

Build all examples in one go with zig build examples; binaries are placed under zig-out/bin/.

Documentation

Comprehensive documentation is available in the doc/ directory:

👉 Start here: doc/README.md

MessagePack helper overview

The znvim.msgpack namespace aims to be the only interface most users need:

const payload = try msgpack.object(allocator, .{
    .name = "my-command",
    .enabled = true,
    .retries = 3,
});

defer msgpack.free(payload, allocator);

const arr = try msgpack.array(allocator, &.{ payload });
const parsed = msgpack.expectArray(arr) catch return error.NotArray;

Use msgpack.encode(allocator, value) for generic encoding of common Zig types, and the expect* / as* helpers when decoding responses.

Development

Run tests:

zig build test

Generate API documentation:

zig build docs

The generated documentation will be in the zig-out/docs/ directory. Open zig-out/docs/index.html in your browser.

Run performance benchmarks:

zig build run-benchmark

To work on the documentation, keep the English README.md and the Chinese translation README.zh.md in sync.

License

MIT


About

neovim remote rpc client implementation with zig

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Languages