Skip to main content

Crate znative

Crate znative 

Source
Expand description

§znative — native plugin SDK for zshrs

zshrs is the first JIT-compiled Unix shell; this crate is what makes it the first compiled shell that hosts third-party plugins written in a native compiled language (Rust) and loaded at runtime — no recompile of the shell, no zsh script glue. A plugin is an ordinary cdylib that the shell dlopens via zmodload -R <path>.

The boundary between host and plugin is a hand-rolled, versioned C ABI (#[repr(C)] structs + extern "C" fn pointers). Both sides depend on THIS crate so they agree on the exact layout. Nothing about Rust’s unstable repr(Rust) layout, allocator, or panic ABI crosses the boundary — only C-representable data.

§Writing a plugin

ⓘ
use znative::{declare_plugin, Args, Host};
use std::os::raw::c_int;

fn hello(host: &Host, args: &Args) -> c_int {
    host.print(&format!("hello from rust, argv={:?}\n", args.to_vec()));
    0
}

declare_plugin! {
    name: "hello",
    version: "0.1.0",
    builtins: { "rhello" => hello },
}

Cargo.toml:

[lib]
crate-type = ["cdylib"]
[dependencies]
znative = "0.12"

cargo build produces libhello.dylib / libhello.so; then inside zshrs: zmodload -R ~/plugins/libhello.dylib and rhello is a live command.

§Host API

Inside a handler, Host is the shell’s callback table:

MethodPurpose
printwrite to the shell’s stdout
evalrun shell code, return its exit status
getvar / setvarread/set a shell scalar parameter
getfunction / addfunctionread a function’s deparsed body / define one (also deparse-as-a-service) — ABI v3
register_builtinregister a command handler dynamically
add_match / install_completionemit a completion candidate / wire a native completion into compsys — ABI v2

Macros§

declare_plugin
Declare a plugin: its identity, the builtins it registers, and the native completions it provides. Expands to the #[no_mangle] extern "C" fn znative_init the host looks for, plus the 'static PluginInfo.

Structs§

Args
Safe view over a builtin’s (argc, argv). argv[0] is the command name.
Host
Safe wrapper over *const HostApi for use inside a builtin. Cheap to construct; borrows the host table.
HostApi
The host API table handed to the plugin. Every field is a C-ABI function pointer into zshrs. Layout is frozen by ABI_VERSION.
PluginInfo
What a plugin returns from its InitFn. The strings must have 'static lifetime (typically string literals via the declare_plugin! macro).

Constants§

ABI_VERSION
ABI version. Bumped on ANY change to HostApi, PluginInfo, BuiltinFn, or InitFn layout/semantics. The host refuses to load a plugin whose abi_version does not match its own — a mismatched struct layout is undefined behaviour, so this is a hard gate, not a warning.
INIT_SYMBOL
The one symbol every plugin cdylib must export. The host resolves it with dlsym after dlopen. Signature is InitFn.

Type Aliases§

BuiltinFn
A plugin-provided command handler.
CompFn
A plugin-provided compsys function override — the native replacement for a shell completion function named _NAME (e.g. _command_names). Same C-ABI shape as BuiltinFn: registered via HostApi::register_compfn and dispatched by the host’s completion router (try_rust_dispatch) in place of the built-in Rust port or the autoloaded shell function. argv[0] is the _NAME; argv[1..] are the completion-function arguments. (ABI v4.)
InitFn
Signature of INIT_SYMBOL. Called exactly once, right after the dylib is loaded. The plugin registers its builtins through host.register_builtin and returns a pointer to a 'static PluginInfo describing itself (or null on failure).