at 24.11-pre 6.5 kB view raw
1{ config, pkgs, lib, ... }: 2 3let 4 inherit (lib) mkOption mkIf types optionalString; 5 6 cfg = config.programs.tmux; 7 8 defaultKeyMode = "emacs"; 9 defaultResize = 5; 10 defaultShortcut = "b"; 11 defaultTerminal = "screen"; 12 13 boolToStr = value: if value then "on" else "off"; 14 15 tmuxConf = '' 16 set -g default-terminal "${cfg.terminal}" 17 set -g base-index ${toString cfg.baseIndex} 18 setw -g pane-base-index ${toString cfg.baseIndex} 19 20 ${optionalString cfg.newSession "new-session"} 21 22 ${optionalString cfg.reverseSplit '' 23 bind v split-window -h 24 bind s split-window -v 25 ''} 26 27 set -g status-keys ${cfg.keyMode} 28 set -g mode-keys ${cfg.keyMode} 29 30 ${optionalString (cfg.keyMode == "vi" && cfg.customPaneNavigationAndResize) '' 31 bind h select-pane -L 32 bind j select-pane -D 33 bind k select-pane -U 34 bind l select-pane -R 35 36 bind -r H resize-pane -L ${toString cfg.resizeAmount} 37 bind -r J resize-pane -D ${toString cfg.resizeAmount} 38 bind -r K resize-pane -U ${toString cfg.resizeAmount} 39 bind -r L resize-pane -R ${toString cfg.resizeAmount} 40 ''} 41 42 ${optionalString (cfg.shortcut != defaultShortcut) '' 43 # rebind main key: C-${cfg.shortcut} 44 unbind C-${defaultShortcut} 45 set -g prefix C-${cfg.shortcut} 46 bind ${cfg.shortcut} send-prefix 47 bind C-${cfg.shortcut} last-window 48 ''} 49 50 setw -g aggressive-resize ${boolToStr cfg.aggressiveResize} 51 setw -g clock-mode-style ${if cfg.clock24 then "24" else "12"} 52 set -s escape-time ${toString cfg.escapeTime} 53 set -g history-limit ${toString cfg.historyLimit} 54 55 ${cfg.extraConfigBeforePlugins} 56 57 ${lib.optionalString (cfg.plugins != []) '' 58 # Run plugins 59 ${lib.concatMapStringsSep "\n" (x: "run-shell ${x.rtp}") cfg.plugins} 60 61 ''} 62 63 ${cfg.extraConfig} 64 ''; 65 66in { 67 ###### interface 68 69 options = { 70 programs.tmux = { 71 72 enable = mkOption { 73 type = types.bool; 74 default = false; 75 description = "Whenever to configure {command}`tmux` system-wide."; 76 relatedPackages = [ "tmux" ]; 77 }; 78 79 aggressiveResize = mkOption { 80 default = false; 81 type = types.bool; 82 description = '' 83 Resize the window to the size of the smallest session for which it is the current window. 84 ''; 85 }; 86 87 baseIndex = mkOption { 88 default = 0; 89 example = 1; 90 type = types.int; 91 description = "Base index for windows and panes."; 92 }; 93 94 clock24 = mkOption { 95 default = false; 96 type = types.bool; 97 description = "Use 24 hour clock."; 98 }; 99 100 customPaneNavigationAndResize = mkOption { 101 default = false; 102 type = types.bool; 103 description = "Override the hjkl and HJKL bindings for pane navigation and resizing in VI mode."; 104 }; 105 106 escapeTime = mkOption { 107 default = 500; 108 example = 0; 109 type = types.int; 110 description = "Time in milliseconds for which tmux waits after an escape is input."; 111 }; 112 113 extraConfigBeforePlugins = mkOption { 114 default = ""; 115 description = '' 116 Additional contents of /etc/tmux.conf, to be run before sourcing plugins. 117 ''; 118 type = types.lines; 119 }; 120 121 extraConfig = mkOption { 122 default = ""; 123 description = '' 124 Additional contents of /etc/tmux.conf, to be run after sourcing plugins. 125 ''; 126 type = types.lines; 127 }; 128 129 historyLimit = mkOption { 130 default = 2000; 131 example = 5000; 132 type = types.int; 133 description = "Maximum number of lines held in window history."; 134 }; 135 136 keyMode = mkOption { 137 default = defaultKeyMode; 138 example = "vi"; 139 type = types.enum [ "emacs" "vi" ]; 140 description = "VI or Emacs style shortcuts."; 141 }; 142 143 newSession = mkOption { 144 default = false; 145 type = types.bool; 146 description = "Automatically spawn a session if trying to attach and none are running."; 147 }; 148 149 reverseSplit = mkOption { 150 default = false; 151 type = types.bool; 152 description = "Reverse the window split shortcuts."; 153 }; 154 155 resizeAmount = mkOption { 156 default = defaultResize; 157 example = 10; 158 type = types.int; 159 description = "Number of lines/columns when resizing."; 160 }; 161 162 shortcut = mkOption { 163 default = defaultShortcut; 164 example = "a"; 165 type = types.str; 166 description = "Ctrl following by this key is used as the main shortcut."; 167 }; 168 169 terminal = mkOption { 170 default = defaultTerminal; 171 example = "screen-256color"; 172 type = types.str; 173 description = '' 174 Set the $TERM variable. Use tmux-direct if italics or 24bit true color 175 support is needed. 176 ''; 177 }; 178 179 secureSocket = mkOption { 180 default = true; 181 type = types.bool; 182 description = '' 183 Store tmux socket under /run, which is more secure than /tmp, but as a 184 downside it doesn't survive user logout. 185 ''; 186 }; 187 188 plugins = mkOption { 189 default = []; 190 type = types.listOf types.package; 191 description = "List of plugins to install."; 192 example = lib.literalExpression "[ pkgs.tmuxPlugins.nord ]"; 193 }; 194 195 withUtempter = mkOption { 196 description = '' 197 Whether to enable libutempter for tmux. 198 This is required so that tmux can write to /var/run/utmp (which can be queried with `who` to display currently connected user sessions). 199 Note, this will add a guid wrapper for the group utmp! 200 ''; 201 default = true; 202 type = types.bool; 203 }; 204 }; 205 }; 206 207 ###### implementation 208 209 config = mkIf cfg.enable { 210 environment = { 211 etc."tmux.conf".text = tmuxConf; 212 213 systemPackages = [ pkgs.tmux ] ++ cfg.plugins; 214 215 variables = { 216 TMUX_TMPDIR = lib.optional cfg.secureSocket ''''${XDG_RUNTIME_DIR:-"/run/user/$(id -u)"}''; 217 }; 218 }; 219 security.wrappers = mkIf cfg.withUtempter { 220 utempter = { 221 source = "${pkgs.libutempter}/lib/utempter/utempter"; 222 owner = "root"; 223 group = "utmp"; 224 setuid = false; 225 setgid = true; 226 }; 227 }; 228 }; 229 230 imports = [ 231 (lib.mkRenamedOptionModule [ "programs" "tmux" "extraTmuxConf" ] [ "programs" "tmux" "extraConfig" ]) 232 ]; 233}