feat(zellij): add zellij configuration

This commit is contained in:
2026-03-14 14:21:13 +01:00
parent ab089afefd
commit bfaaee0f36
4 changed files with 439 additions and 1 deletions

View File

@@ -78,6 +78,7 @@ in {
./fish.nix
./starship.nix
./tmux.nix
./zellij.nix
./zsh.nix
./zoxide.nix
];

View File

@@ -0,0 +1,173 @@
{
pkgs,
lib,
config,
...
}:
with lib; let
cfg = config.home.shell.zellij;
isEmpty = list: list == [];
keybind = {
options = {
bind = mkOption {
type = types.either types.str (types.listOf types.str);
example = "Alt j";
description = "Value used as a string after `bind` in zellij config";
};
actions = mkOption {
type = with types; let
allowed = oneOf [int str];
in
attrsOf (either (listOf allowed) allowed);
default = {};
example = {
SwitchToMode = ["normal"];
SwitchFocus = [];
PaneNameInput = [0];
};
};
useUnlockFirst = mkOption {
type = types.bool;
default = false;
description = ''
Go back to locked mode after the actions are done.
Only works when `config.home.shell.zellij.useUnlockFirst` is true.
'';
};
};
};
convertBind = item: {
bind = let
useUnlockFirst = cfg.useUnlockFirst && item.useUnlockFirst;
children =
mapAttrsToList (action: args: let
actualArgs =
if isEmpty args
then {}
else {_args = lists.toList args;};
in {"${action}" = actualArgs;})
(item.actions
// (
if useUnlockFirst
then {SwitchToMode = ["locked"];}
else {}
));
in {
_args = lists.toList item.bind;
_children = children;
};
};
keybindsModule = {
options = mergeAttrsList (forEach [
"normal"
"locked"
"resize"
"pane"
"move"
"tab"
"scroll"
"search"
"entersearch"
"renametab"
"renamepane"
"session"
"tmux"
]
(x: {
"${x}" = mkOption {
type = types.listOf (types.submodule keybind);
default = [];
};
}));
};
makeKeybinds = keybinds: let
values =
attrsets.concatMapAttrs (
mode: binds:
if (isEmpty binds)
then {}
else {
"${mode}"._children = lists.forEach binds convertBind;
}
)
keybinds;
in
if values == {}
then {}
else {
keybinds = values;
};
in {
options.home.shell.zellij = let
jsonFormat = pkgs.formats.yaml {};
in {
enable = mkEnableOption "Enable Zellij";
clearDefaultKeybinds = mkEnableOption "Clear default keybinds";
settings = mkOption {
inherit (jsonFormat) type;
default = {};
};
layouts = mkOption {
inherit (jsonFormat) type;
default = {};
};
extraSettings = mkOption {
type = types.lines;
default = "";
description = ''
Extra configuration lines to add to `$XDG_CONFIG_HOME/zellij/config.kdl`
'';
};
useUnlockFirst = mkEnableOption "Use Unlock-First (non-colliding) behaviour by default";
plugins = mkOption {
type = types.listOf (types.submodule plugin);
default = {};
example = [
{name = "about";}
{
name = "filepicker";
location = "zellij:strider";
options = {
cwd = "/";
};
}
];
};
keybinds = mkOption {
type = types.submodule keybindsModule;
default = {};
example = {
pane = [
{
bind = "c";
actions = [
{
action = "SwitchToMode";
args = ["renamepane"];
}
{
action = "PaneNameInput";
args = [0];
}
];
}
];
};
};
};
config.programs.zellij = mkIf cfg.enable {
inherit (cfg) enable layouts;
extraConfig = cfg.extraSettings;
settings = let
resetKeybinds =
if cfg.clearDefaultKeybinds
then {
keybinds._props.clear-defaults = true;
}
else {};
keybinds = makeKeybinds cfg.keybinds;
in
cfg.settings // resetKeybinds // keybinds;
};
}

View File

@@ -7,7 +7,7 @@
with lib; let
cfg = config.home.phundrak;
in {
imports = [../modules];
imports = [../modules ./zellij.nix];
options.home.phundrak = {
sshKey = {

264
users/phundrak/zellij.nix Normal file
View File

@@ -0,0 +1,264 @@
{lib, ...}: {
home.shell.zellij = with lib; {
enable = true;
clearDefaultKeybinds = true;
useUnlockFirst = true;
settings.copy_on_select = true;
extraSettings = ''
plugins {
about location="zellij:about"
compact-bar location="zellij:compact-bar"
configuration location="zellij:configuration"
filepicker location="zellij:strider" {
cwd "/"
}
plugin-manager location="zellij:plugin-manager"
session-manager location="zellij:session-manager"
status-bar location="zellij:status-bar"
strider location="zellij:strider"
tab-bar location="zellij:tab-bar"
welcome-screen location="zellij:session-manager" {
welcome_screen true
}
}
'';
keybinds = let
# bépo layout
left = ["c" "Left"];
down = ["t" "Down"];
up = ["s" "Up"];
right = ["r" "Right"];
numRow = ["\"" "«" "»" "(" ")" "@" "+" "-" "/" "*"];
in {
locked = [
{
bind = "Ctrl Alt g";
actions = {SwitchToMode = "normal";};
}
];
pane = [
{
bind = left;
actions = {MoveFocus = "Left";};
}
{
bind = down;
actions = {MoveFocus = "Down";};
}
{
bind = up;
actions = {MoveFocus = "Up";};
}
{
bind = right;
actions = {MoveFocus = "Right";};
}
{
bind = "n";
actions = {NewPane = [];};
useUnlockFirst = true;
}
{
bind = "T";
actions = {NewPane = "Down";};
useUnlockFirst = true;
}
{
bind = "R";
actions = {NewPane = "Right";};
useUnlockFirst = true;
}
{
bind = "S";
actions = {NewPane = "stacked";};
useUnlockFirst = true;
}
{
bind = "N";
actions = {SwitchToMode = "normal";};
}
{
bind = "e";
actions = {TogglePaneEmbedOrFloating = [];};
useUnlockFirst = true;
}
{
bind = "i";
actions = {TogglePanePinned = [];};
}
{
bind = "f";
actions = {ToggleFocusFullscreen = [];};
useUnlockFirst = true;
}
{
bind = "F";
actions = {ToggleFloatingPanes = [];};
}
{
bind = "q";
actions = {CloseFocus = [];};
useUnlockFirst = true;
}
{
bind = "p";
actions = {SwitchToMode = "normal";};
}
{
bind = "P";
actions = {
SwitchToMode = "renamepane";
PaneNameInput = 0;
};
}
{
bind = "z";
actions = {TogglePaneFrames = [];};
useUnlockFirst = true;
}
{
bind = "tab";
actions = {SwitchFocus = [];};
}
];
resize = [
{
bind = "n";
actions = {SwitchToMode = "locked";};
}
{
bind = left;
actions = {Resize = "Increase Left";};
}
{
bind = down;
actions = {Resize = "Increase Down";};
}
{
bind = up;
actions = {Resize = "Increase Up";};
}
{
bind = right;
actions = {Resize = "Increase Right";};
}
{
bind = "C";
actions = {Resize = "Decrease Left";};
}
{
bind = "T";
actions = {Resize = "Decrease Down";};
}
{
bind = "S";
actions = {Resize = "Decrease Up";};
}
{
bind = "R";
actions = {Resize = "Decrease Right";};
}
{
bind = "+";
actions = {Resize = "Increase";};
}
{
bind = "-";
actions = {Resize = "Decrease";};
}
];
move = [
{
bind = left;
actions = {MovePane = "left";};
}
{
bind = down;
actions = {MovePane = "down";};
}
{
bind = up;
actions = {MovePane = "up";};
}
{
bind = right;
actions = {MovePane = "right";};
}
{
bind = "m";
actions = {SwitchToMode = "normal";};
}
{
bind = ["n" "tab"];
actions = {MovePane = [];};
}
{
bind = "p";
actions = {MovePaneBackwards = [];};
}
];
tab =
[
{
bind = left ++ up;
actions = {GoToPreviousTab = [];};
}
{
bind = down ++ right;
actions = {GoToNextTab = [];};
}
{
bind = "[";
actions = {BreakPaneLeft = [];};
useUnlockFirst = true;
}
{
bind = "]";
actions = {BreakPaneRight = [];};
useUnlockFirst = true;
}
{
bind = "b";
actions = {BreakPane = [];};
useUnlockFirst = true;
}
{
bind = "n";
actions = {NewTab = [];};
useUnlockFirst = true;
}
{
bind = "R";
actions = {
SwitchToMode = "renametab";
TabNameInput = 0;
};
}
{
bind = "s";
actions = {ToggleActiveSyncTab = [];};
useUnlockFirst = true;
}
{
bind = "T";
actions = {SwitchToMode = "normal";};
}
{
bind = "x";
actions = {CloseTab = [];};
useUnlockFirst = true;
}
{
bind = "tab";
actions = {ToggleTab = [];};
}
]
++ (lists.imap1 (i: key: {
bind = key;
actions = {GoToTab = i;};
useUnlockFirst = true;
})
numRow);
};
};
}