Zellij: Difference between revisions
zellij: init |
m style fixes and improvements (using C as a syntax highlighting language for KDL code is a hack, but IMO looks more readable than no colors) |
||
| Line 5: | Line 5: | ||
==== Shell ==== | ==== Shell ==== | ||
To temporarily use zellij in a shell environment without modifying your system configuration, you can run: | To temporarily use zellij in a shell environment without modifying your system configuration, you can run: | ||
<syntaxhighlight lang=console> | |||
$ nix-shell -p zellij | |||
</syntaxhighlight> | |||
This makes the zellij available in your current shell. You can then launch zellij by typing <code>zellij</code>. | This makes the zellij available in your current shell. You can then launch zellij by typing <code>zellij</code>. | ||
| Line 77: | Line 79: | ||
This will generate <code>~/.config/zellij/config.kdl</code>, with something like this: | This will generate <code>~/.config/zellij/config.kdl</code>, with something like this: | ||
{{file|~/.config/zellij/config.kdl| | {{file|~/.config/zellij/config.kdl|c| | ||
<nowiki> | <nowiki> | ||
load_plugins { | load_plugins { | ||
| Line 109: | Line 111: | ||
To add a new plugin, you can just use [https://github.com/nix-community/nix-init nix-init] like this: | To add a new plugin, you can just use [https://github.com/nix-community/nix-init nix-init] like this: | ||
<syntaxhighlight lang=console> | |||
< | |||
$ nix-init pkgs/by-name/ze/zellij/plugins/rust/my-plugin-name.nix | $ nix-init pkgs/by-name/ze/zellij/plugins/rust/my-plugin-name.nix | ||
Enter url | Enter url | ||
| Line 122: | Line 123: | ||
How should this package be built? | How should this package be built? | ||
❯ buildRustPackage - cargoHash | ❯ buildRustPackage - cargoHash | ||
</ | </syntaxhighlight> | ||
If the repository name starts with <code>zellij</code>, you should omit it in the actual package name. <code>zellijPlugins.autolock</code> looks better than <code>zellijPlugins.zellij-autolock</code>. | If the repository name starts with <code>zellij</code>, you should omit it in the actual package name. <code>zellijPlugins.autolock</code> looks better than <code>zellijPlugins.zellij-autolock</code>. | ||
Latest revision as of 17:53, 19 July 2026
Zellij is a terminal multiplexer: it enables a number of terminals (or windows), each running a separate program, to be created, accessed, and controlled from a single screen. Zellij may be detached from a screen and continue running in the background, then later reattached.
Installation
Shell
To temporarily use zellij in a shell environment without modifying your system configuration, you can run:
$ nix-shell -p zellij
This makes the zellij available in your current shell. You can then launch zellij by typing zellij.
Configuration
zellij can be configured using Home Manager:
As an example:
programs.zellij = {
enable = true;
# automatically start zellij when opening a new terminal
enableBashIntegration = true;
enableFishIntegration = true;
enableZshIntegration = true;
# zellij uses KDL as its configuration language,
# see also https://zellij.dev/documentation/configuration.html
settings = {
theme = "custom";
themes.custom.fg = "#ffffff";
keybinds._props.clear-defaults = true;
keybinds.pane._children = [
};
# extra settings as a raw string
# they are appended to the end of the file
extraConfig = ''
keybinds {
pane {
bind "h" "Left" { MoveFocus "Left"; }
bind "l" "Right" { MoveFocus "Right"; }
bind "j" "Down" { MoveFocus "Down"; }
bind "k" "Up" { MoveFocus "Up"; }
}
}
'';
};
Using Plugins
Zellij offers a WebAssembly / WASI plugin system, allowing plugin developers to develop plugins in many different languages.
Plugins can be configured using programs.zellij.plugins. In nixpkgs, they can be found in the zellijPlugins namespace.
programs.zellij = {
enable = true;
plugins = with zellijPlugins; [ vim-zellij-navigator ];
settings ={
plugins = {
vim-zellij-navigator = {
vim_commands = "v|nvim|vim|testNvim";
};
};
};
extraConfig = ''
keybinds {
shared_among "normal" "locked" "scroll" {
bind "Ctrl j" {
MessagePlugin "vim-zellij-navigator" {
name "move_focus";
payload "down";
};
}
}
}
'';
};
This will generate ~/.config/zellij/config.kdl, with something like this:
load_plugins {
vim-zellij-navigator
}
plugins {
vim-zellij-navigator location="file:/home/perchun/.config/zellij/plugins/vim-zellij-navigator.wasm" {
vim_commands "v|nvim|vim|testNvim"
}
}
// extraConfig
keybinds {
shared_among "normal" "locked" "scroll" {
bind "Ctrl j" {
MessagePlugin "vim-zellij-navigator" {
name "move_focus";
payload "down";
};
}
}
}
Packaging Plugins
All plugins are packaged in the pkgs/by-name/ze/zellij/plugins/ folder. Currently, only Rust plugins are packaged, but if you figure out how to package other languages, contributions are welcome.
To add a new plugin, you can just use nix-init like this:
$ nix-init pkgs/by-name/ze/zellij/plugins/rust/my-plugin-name.nix
Enter url
❯ https://github.com/hello/my-plugin-name
Enter tag or revision (defaults to v0.1.0)
❯ v0.1.0
Enter version
❯ 0.1.0
Enter pname
❯ my-plugin-name
How should this package be built?
❯ buildRustPackage - cargoHash
If the repository name starts with zellij, you should omit it in the actual package name. zellijPlugins.autolock looks better than zellijPlugins.zellij-autolock.
After you have generated the initial definition file, remove all dependencies that were automatically set by nix-init. They are not needed when compiling a WASM binary. If the plugin depends on something at runtime, read the next section.
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 for WASI, everything that the plugin gets as derivation arguments is also compiled for WASI. Some packages (for example coreutils) might not be available on WASI, so we need to use pkgsBuildBuild attrs set (which points to the user's system).
# assume we build the plugin on an 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=";
# specify runtime dependencies here
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; [ you ];
};
})
If you are wondering why pkgsBuildBuild is named like that, refer to the docs on cross-compilation.
Overriding plugins
Plugins use a wrapper for additional post-processing, like stripping unnecessary information from pluginDrv.name. So naїve override won't work, as it overrides the wrapper and not the plugin itself. Instead, you should override the unwrapped version and then pass that to the wrapper:
final: prev: {
zellijPlugins = prev.zellijPlugins // {
# wrap our overrode package
zjstatus = prev.zellijPlugins.wrapper "zjstatus" (
# override unwrapped package
prev.zellijPlugins.zjstatus.unwrapped.overrideAttrs (
oldAttrs:
let
src = final.fetchFromGitHub {
owner = "dj95";
repo = "zjstatus";
rev = "17609e498f88e674b846b844b48ad1dc545fddcf";
hash = "sha256-/LsFGF0BAYdiVVQZ/8vjo6IXuSsYS+ueIWHN47NHEAc=";
};
in
{
version = "0-unstable-2026-06-03";
inherit src;
# override cargoHash if it is needed
cargoDeps = final.rustPlatform.fetchCargoVendor {
inherit src;
hash = "sha256-+UYNIPrRYUYwxHk227PDo5vdAqho8SMm80o7UqSdZ3g=";
};
}
)
);
};
}