zellijPlugins: init (#511825)

This commit is contained in:
Matthias Beyer
2026-05-27 06:08:40 +00:00
committed by GitHub
11 changed files with 386 additions and 88 deletions

View File

@@ -527,3 +527,6 @@ pkgs/by-name/wa/warp-terminal/ @emilytrau @imadnyc @FlameFlag @johnrtitor
# Radicle
/pkgs/build-support/fetchradicle/ @NixOS/radicle
/pkgs/build-support/fetchradiclepatch/ @NixOS/radicle
# Zellij plugins
/pkgs/by-name/ze/zellij/plugins/ @PerchunPak

View File

@@ -1,96 +1,35 @@
{
lib,
stdenv,
rustPlatform,
fetchFromGitHub,
mandown,
installShellFiles,
pkg-config,
curl,
openssl,
writableTmpDirAsHomeHook,
versionCheckHook,
callPackage,
makeBinaryWrapper,
stdenvNoCC,
nix-update-script,
extraPackages ? [ ],
}:
rustPlatform.buildRustPackage (finalAttrs: {
let
unwrapped = callPackage ./unwrapped.nix { };
in
stdenvNoCC.mkDerivation {
inherit (unwrapped) version meta;
pname = "zellij";
version = "0.44.3";
__structuredAttrs = true;
strictDeps = true;
src = fetchFromGitHub {
owner = "zellij-org";
repo = "zellij";
tag = "v${finalAttrs.version}";
hash = "sha256-r8GAOiau4CZPVotFmsBQJOvEu+t0Bu9UCYAOs18i3Kg=";
src = unwrapped;
dontUnpack = true;
nativeBuildInputs = [ makeBinaryWrapper ];
buildPhase = ''
cp -rs --no-preserve=mode "$src" "$out"
wrapProgram "$out/bin/zellij" \
--prefix PATH : '${lib.makeBinPath extraPackages}'
'';
passthru = unwrapped.passthru or { } // {
inherit unwrapped;
updateScript = nix-update-script { attrPath = "zellij.unwrapped"; };
};
# Remove the `vendored_curl` feature in order to link against the libcurl from nixpkgs instead of
# the vendored one
postPatch = ''
substituteInPlace Cargo.toml \
--replace-fail ', "vendored_curl"' ""
'';
cargoHash = "sha256-966FpfSsF9I10SrYe3+YNsfM2kLLv+gd0/Aw8vLp4Lk=";
env.OPENSSL_NO_VENDOR = 1;
nativeBuildInputs = [
mandown
installShellFiles
pkg-config
(lib.getDev curl)
];
buildInputs = [
curl
openssl
];
nativeCheckInputs = [
writableTmpDirAsHomeHook
];
nativeInstallCheckInputs = [
versionCheckHook
];
doInstallCheck = true;
# Ensure that we don't vendor curl, but instead link against the libcurl from nixpkgs
installCheckPhase = lib.optionalString (stdenv.hostPlatform.libc == "glibc") ''
runHook preInstallCheck
ldd "$out/bin/zellij" | grep libcurl.so
runHook postInstallCheck
'';
postInstall = ''
mandown docs/MANPAGE.md > zellij.1
installManPage zellij.1
''
+ lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
installShellCompletion --cmd $pname \
--bash <($out/bin/zellij setup --generate-completion bash) \
--fish <($out/bin/zellij setup --generate-completion fish) \
--zsh <($out/bin/zellij setup --generate-completion zsh)
'';
passthru.updateScript = nix-update-script { };
meta = {
description = "Terminal workspace with batteries included";
homepage = "https://zellij.dev/";
changelog = "https://github.com/zellij-org/zellij/blob/v${finalAttrs.version}/CHANGELOG.md";
license = with lib.licenses; [ mit ];
maintainers = with lib.maintainers; [
therealansh
_0x4A6F
abbe
matthiasbeyer
ryan4yin
];
mainProgram = "zellij";
};
})
}

View File

@@ -0,0 +1,83 @@
# Zellij plugins
Zellij offers a Webassembly / WASI plugin system, allowing plugin developers to
develop plugins in many different languages. Currently, nixpkgs focuses only on
Rust plugins (the majority of them).
Most of the plugins were generated using `nix-init` on [awesome-zellij].
Excluded plugins from that list (should be packaged later anyway):
- [bar-theme-config](https://github.com/allisonhere/zellij-bar-theme-config): not a plugin, but a separate application
- [fzf-zellij](https://github.com/k-kuroguro/fzf-zellij): [closed source](https://github.com/k-kuroguro/fzf-zellij/issues/1)
- [gitpod-zellij](https://github.com/ona-samples/gitpod.zellij): not a plugin, but a separate application?
- [opencode-zellij-namer](https://github.com/24601/opencode-zellij-namer): written in TypeScript, not Rust
- [theme-configurator](https://rosmur.github.io/zellij-theme-configurator/): not a plugin, but a separate application
- [yazelix](https://github.com/luccahuguet/yazelix): written in Nushell
- [zeco](https://github.com/julianbuettner/zeco): not a plugin, but a separate application?
- [zellij-load](https://github.com/Christian-Prather/zellij-load): has daemon, so that needs to be packaged too
- [zellij-vscode-toolkit](https://github.com/atoolz/zellij-vscode-toolkit): not a plugin, but a VSCode plugin
- [zellix](https://github.com/EmeraldPandaTurtle/zellix): written in Nushell
- [zj-quit](https://github.com/cristiand391/zj-quit): archived
- [zj-status-bar](https://github.com/cristiand391/zj-status-bar): archived
- [zrw](https://github.com/ivoronin/zrw): written in Go
Contributions are welcome!
[awesome-zellij]: https://github.com/zellij-org/awesome-zellij/blob/95fce2c02a2dcca33e4972eed3eba64d516693c9/README.md
## Specifying runtime dependencies
Runtime dependencies are packages, that will be used by the plugin inside
a Zellij session. Those are specified in `passthru.runtimeDeps` attribute from
`pkgsBuildBuild` attrset.
Since we compile all plugins on WASI, everything that the plugin gets as
derivation arguments are also get compiled for WASI. However, `coreutils` is
not available on WASI and so is the vast majority of packages. This is why
runtime dependencies need to be specified from `pkgsBuildBuild` attrs set
(which points to the user's system).
```nix
# assume we build the plugin on a x86_64-linux machine
{
lib,
fetchFromGitHub,
rustPlatform,
# these will be compiled for WASI, not x86_64-linux!
just,
bacon,
# but pkgsBuildBuild points to x86_64-linux
pkgsBuildBuild,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "jbz";
version = "0.39.0";
src = fetchFromGitHub {
owner = "nim65s";
repo = "jbz";
tag = "v${finalAttrs.version}";
hash = "sha256-3n3Bv3YDb1+MYJTTAmMkIgGY7kX9IVUoDNV4c/n0Ydo=";
};
cargoHash = "sha256-U+P2LlhmXwaZy2a2eigrg545HTuV1T01jZfUOEUQ5+w=";
# this is the only way how to specify dependencies
passthru.runtimeDeps = with pkgsBuildBuild; [
bacon
just
];
meta = {
description = "Display your Just commands wrapped in Bacon";
homepage = "https://github.com/nim65s/jbz";
changelog = "https://github.com/nim65s/jbz/releases/tag/${finalAttrs.src.tag}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ PerchunPak ];
};
})
```
If you are wondering why `pkgsBuildBuild` is named like that, refer to
[the docs on cross-compilation](https://nixos.org/manual/nixpkgs/unstable/#possible-dependency-types).

View File

@@ -0,0 +1,53 @@
{
lib,
callPackage,
nix-update-script,
stdenvNoCC,
zellij,
}:
let
# wrapper for changing the output path from directory to single file
# from /nix/store/...-zsm-static-wasm32-unknown-wasi-0.4.1/bin/zsm.wasm
# to /nix/store/...-zellij-plugin-zsm-0.4.1.wasm
wrapper =
attrName: pkg:
assert lib.assertMsg (
!((lib.hasAttr "runtimeDeps" pkg) && (!lib.hasAttr "runtimeDeps" pkg.passthru))
) "Plugin ${pkg.pname} has specified `runtimeDeps` instead of `passthru.runtimeDeps`";
stdenvNoCC.mkDerivation (finalAttrs: {
inherit (pkg)
pname
version
;
name = "zellij-plugin-${finalAttrs.pname}-${finalAttrs.version}.wasm";
src = pkg;
dontUnpack = true;
buildPhase = ''
resultFile=$(find "$src" -name '*.wasm')
if [ $(echo "$resultFile" | wc -l) -ne 1 ]; then
echo "The unwrapped plugin ($src) contains more than one WASM file"
echo "$resultFile"
exit 1
fi
# there should probably be `ln -s` here, but it produces a permission error for me
cp "$resultFile" "$out"
'';
passthru = pkg.passthru or { } // {
unwrapped = pkg;
updateScript = pkg.passthru.updateScript or nix-update-script {
attrPath = "zellijPlugins.${attrName}.unwrapped";
};
};
meta = pkg.meta // {
maintainers = pkg.meta.maintainers or [ ] ++ [ lib.maintainers.PerchunPak ];
platforms = pkg.meta.platforms or zellij.platforms;
};
});
rustPlugins = lib.mapAttrs wrapper (callPackage ./rust { });
in
rustPlugins // { inherit wrapper; }

View File

@@ -0,0 +1,25 @@
{ pkgsCross, lib }:
let
root = ./.;
pkgs' = pkgsCross.wasi32;
call = name: override (pkgs'.callPackage (root + "/${name}") { });
override =
pkg:
pkg.overrideAttrs (old: {
# these hacks are needed until https://github.com/NixOS/nixpkgs/pull/463720#pullrequestreview-3841639011 is resolved
nativeBuildInputs = old.nativeBuildInputs or [ ] ++ [ pkgs'.lld ];
env = old.env or { } // {
RUSTFLAGS = old.env.RUSTFLAGS or "" + " -C linker=wasm-ld";
};
meta = old.meta or { } // {
platforms = old.meta.platforms or lib.platforms.linux;
};
});
in
lib.pipe root [
builtins.readDir
(lib.filterAttrs (name: _: name != "default.nix" && name != "README.md"))
(lib.mapAttrs' (name: _: lib.nameValuePair (lib.removeSuffix ".nix" name) (call name)))
]

View File

@@ -0,0 +1,32 @@
{
lib,
fetchFromGitHub,
rustPlatform,
pkgsBuildBuild,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "jbz";
version = "0.39.0";
src = fetchFromGitHub {
owner = "nim65s";
repo = "jbz";
tag = "v${finalAttrs.version}";
hash = "sha256-3n3Bv3YDb1+MYJTTAmMkIgGY7kX9IVUoDNV4c/n0Ydo=";
};
cargoHash = "sha256-U+P2LlhmXwaZy2a2eigrg545HTuV1T01jZfUOEUQ5+w=";
passthru.runtimeDeps = with pkgsBuildBuild; [
bacon
just
];
meta = {
description = "Display your Just commands wrapped in Bacon";
homepage = "https://github.com/nim65s/jbz";
changelog = "https://github.com/nim65s/jbz/releases/tag/${finalAttrs.src.tag}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ PerchunPak ];
};
})

View File

@@ -0,0 +1,26 @@
{
lib,
rustPlatform,
fetchFromGitHub,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "vim-zellij-navigator";
version = "0.3.0";
src = fetchFromGitHub {
owner = "hiasr";
repo = "vim-zellij-navigator";
tag = finalAttrs.version;
hash = "sha256-1zzY1Z8ZpiNTdFW+gKRYaRR+oCzMnbJA2szY0k24bGg=";
};
cargoHash = "sha256-AbfgDhQEbm5qULw2HHxG5EMCYdML4VhHxJaAqP2g3u0=";
meta = {
description = "Seamless navigation between Zellij panes and Vim splits";
homepage = "https://github.com/hiasr/vim-zellij-navigator";
changelog = "https://github.com/hiasr/vim-zellij-navigator/releases/tag/${finalAttrs.src.tag}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ PerchunPak ];
};
})

View File

@@ -0,0 +1,12 @@
{ callPackage }:
# zjstatus and zjframes are contained in the same repository, but as different crates
let
zjstatus = callPackage ./zjstatus.nix { _binaryName = "zjframes"; };
in
zjstatus.overrideAttrs (old: {
pname = "zjframes";
meta = old.meta // {
description = "Toggle Zellij pane frames based on different conditions";
};
})

View File

@@ -0,0 +1,30 @@
{
lib,
fetchFromGitHub,
rustPlatform,
_binaryName ? "zjstatus", # passed to `cargo build --bin`
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "zjstatus";
version = "0.23.0";
src = fetchFromGitHub {
owner = "dj95";
repo = "zjstatus";
tag = "v${finalAttrs.version}";
hash = "sha256-sjMs63OaRhwCrl46v1A+K2EJdqnw63Pc7BMnHqiU790=";
};
cargoHash = "sha256-jg7EpcA3o/Qdb1eIspZQI3TX3+7gc3YX+FB4l4FZX44=";
cargoBuildFlags = [ "--bin=${_binaryName}" ];
meta = {
description = "Configurable statusbar plugin for Zellij";
homepage = "https://github.com/dj95/zjstatus";
changelog = "https://github.com/dj95/zjstatus/releases/tag/${finalAttrs.src.tag}";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ PerchunPak ];
};
})

View File

@@ -0,0 +1,93 @@
{
lib,
stdenv,
rustPlatform,
fetchFromGitHub,
mandown,
installShellFiles,
pkg-config,
curl,
openssl,
writableTmpDirAsHomeHook,
versionCheckHook,
}:
rustPlatform.buildRustPackage (finalAttrs: {
pname = "zellij-unwrapped";
version = "0.44.3";
__structuredAttrs = true;
src = fetchFromGitHub {
owner = "zellij-org";
repo = "zellij";
tag = "v${finalAttrs.version}";
hash = "sha256-r8GAOiau4CZPVotFmsBQJOvEu+t0Bu9UCYAOs18i3Kg=";
};
# Remove the `vendored_curl` feature in order to link against the libcurl from nixpkgs instead of
# the vendored one
postPatch = ''
substituteInPlace Cargo.toml \
--replace-fail ', "vendored_curl"' ""
'';
cargoHash = "sha256-966FpfSsF9I10SrYe3+YNsfM2kLLv+gd0/Aw8vLp4Lk=";
env.OPENSSL_NO_VENDOR = 1;
nativeBuildInputs = [
mandown
installShellFiles
pkg-config
(lib.getDev curl)
];
buildInputs = [
curl
openssl
];
nativeCheckInputs = [
writableTmpDirAsHomeHook
];
nativeInstallCheckInputs = [
versionCheckHook
];
doInstallCheck = true;
# Ensure that we don't vendor curl, but instead link against the libcurl from nixpkgs
installCheckPhase = lib.optionalString (stdenv.hostPlatform.libc == "glibc") ''
runHook preInstallCheck
ldd "$out/bin/zellij" | grep libcurl.so
runHook postInstallCheck
'';
postInstall = ''
mandown docs/MANPAGE.md > zellij.1
installManPage zellij.1
''
+ lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
installShellCompletion --cmd zellij \
--bash <($out/bin/zellij setup --generate-completion bash) \
--fish <($out/bin/zellij setup --generate-completion fish) \
--zsh <($out/bin/zellij setup --generate-completion zsh)
'';
meta = {
description = "Terminal workspace with batteries included";
homepage = "https://zellij.dev/";
changelog = "https://github.com/zellij-org/zellij/blob/v${finalAttrs.version}/CHANGELOG.md";
license = with lib.licenses; [ mit ];
maintainers = with lib.maintainers; [
therealansh
_0x4A6F
abbe
matthiasbeyer
ryan4yin
];
mainProgram = "zellij";
};
})

View File

@@ -3467,6 +3467,8 @@ with pkgs;
nvidiaSupport = true;
};
zellijPlugins = recurseIntoAttrs (callPackage ../by-name/ze/zellij/plugins { });
zstd = callPackage ../tools/compression/zstd {
cmake = buildPackages.cmakeMinimal;
};