2018-09-14 16:14:39 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
|
|
cfg = config.programs.tmux;
|
|
|
|
|
2020-04-25 12:40:32 +00:00
|
|
|
pluginName = p: if types.package.check p then p.pname else p.plugin.pname;
|
2018-09-14 16:14:39 +00:00
|
|
|
|
|
|
|
pluginModule = types.submodule {
|
|
|
|
options = {
|
|
|
|
plugin = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
description = "Path of the configuration file to include.";
|
|
|
|
};
|
|
|
|
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
description = "Additional configuration for the associated plugin.";
|
|
|
|
default = "";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
defaultKeyMode = "emacs";
|
|
|
|
defaultResize = 5;
|
|
|
|
defaultShortcut = "b";
|
|
|
|
defaultTerminal = "screen";
|
2019-10-15 02:23:32 +00:00
|
|
|
defaultShell = null;
|
2019-02-10 01:19:56 +00:00
|
|
|
|
|
|
|
boolToStr = value: if value then "on" else "off";
|
|
|
|
|
|
|
|
tmuxConf = ''
|
2020-04-25 15:02:49 +00:00
|
|
|
${optionalString cfg.sensibleOnTop ''
|
|
|
|
# ============================================= #
|
|
|
|
# Start with defaults from the Sensible plugin #
|
|
|
|
# --------------------------------------------- #
|
|
|
|
run-shell ${pkgs.tmuxPlugins.sensible.rtp}
|
|
|
|
# ============================================= #
|
|
|
|
''}
|
2019-02-10 01:19:56 +00:00
|
|
|
set -g default-terminal "${cfg.terminal}"
|
|
|
|
set -g base-index ${toString cfg.baseIndex}
|
|
|
|
setw -g pane-base-index ${toString cfg.baseIndex}
|
2019-10-15 02:23:32 +00:00
|
|
|
${optionalString (cfg.shell != null) ''
|
|
|
|
# We need to set default-shell before calling new-session
|
|
|
|
set -g default-shell "${cfg.shell}"
|
|
|
|
''}
|
2019-02-10 01:19:56 +00:00
|
|
|
${optionalString cfg.newSession "new-session"}
|
|
|
|
|
|
|
|
${optionalString cfg.reverseSplit ''
|
|
|
|
bind v split-window -h
|
|
|
|
bind s split-window -v
|
|
|
|
''}
|
|
|
|
|
|
|
|
set -g status-keys ${cfg.keyMode}
|
|
|
|
set -g mode-keys ${cfg.keyMode}
|
|
|
|
|
|
|
|
${optionalString (cfg.keyMode == "vi" && cfg.customPaneNavigationAndResize) ''
|
|
|
|
bind h select-pane -L
|
|
|
|
bind j select-pane -D
|
|
|
|
bind k select-pane -U
|
|
|
|
bind l select-pane -R
|
|
|
|
|
|
|
|
bind -r H resize-pane -L ${toString cfg.resizeAmount}
|
|
|
|
bind -r J resize-pane -D ${toString cfg.resizeAmount}
|
|
|
|
bind -r K resize-pane -U ${toString cfg.resizeAmount}
|
|
|
|
bind -r L resize-pane -R ${toString cfg.resizeAmount}
|
|
|
|
''}
|
|
|
|
|
2020-05-20 13:23:00 +00:00
|
|
|
${if cfg.prefix != null
|
|
|
|
then ''
|
|
|
|
# rebind main key: ${cfg.prefix}
|
|
|
|
unbind C-${defaultShortcut}
|
|
|
|
set -g prefix ${cfg.prefix}
|
|
|
|
bind ${cfg.prefix} send-prefix
|
|
|
|
''
|
|
|
|
else optionalString (cfg.shortcut != defaultShortcut) ''
|
|
|
|
# rebind main key: C-${cfg.shortcut}
|
|
|
|
unbind C-${defaultShortcut}
|
|
|
|
set -g prefix C-${cfg.shortcut}
|
|
|
|
bind ${cfg.shortcut} send-prefix
|
|
|
|
bind C-${cfg.shortcut} last-window
|
|
|
|
''
|
|
|
|
}
|
2019-02-10 01:19:56 +00:00
|
|
|
|
2019-06-04 11:21:20 +00:00
|
|
|
${optionalString cfg.disableConfirmationPrompt ''
|
|
|
|
bind-key & kill-window
|
|
|
|
bind-key x kill-pane
|
|
|
|
''}
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
setw -g aggressive-resize ${boolToStr cfg.aggressiveResize}
|
|
|
|
setw -g clock-mode-style ${if cfg.clock24 then "24" else "12"}
|
|
|
|
set -s escape-time ${toString cfg.escapeTime}
|
|
|
|
set -g history-limit ${toString cfg.historyLimit}
|
|
|
|
'';
|
|
|
|
|
2020-04-25 15:02:49 +00:00
|
|
|
configPlugins = {
|
|
|
|
assertions = [(
|
|
|
|
let
|
|
|
|
hasBadPluginName = p: !(hasPrefix "tmuxplugin" (pluginName p));
|
|
|
|
badPlugins = filter hasBadPluginName cfg.plugins;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
assertion = badPlugins == [];
|
|
|
|
message =
|
|
|
|
"Invalid tmux plugin (not prefixed with \"tmuxplugins\"): "
|
|
|
|
+ concatMapStringsSep ", " pluginName badPlugins;
|
|
|
|
}
|
|
|
|
)];
|
|
|
|
|
2021-04-23 07:25:13 +00:00
|
|
|
xdg.configFile."tmux/tmux.conf".text = ''
|
2020-04-25 15:02:49 +00:00
|
|
|
# ============================================= #
|
|
|
|
# Load plugins with Home Manager #
|
|
|
|
# --------------------------------------------- #
|
|
|
|
|
|
|
|
${(concatMapStringsSep "\n\n" (p: ''
|
|
|
|
# ${pluginName p}
|
|
|
|
# ---------------------
|
|
|
|
${p.extraConfig or ""}
|
|
|
|
run-shell ${
|
|
|
|
if types.package.check p
|
|
|
|
then p.rtp
|
|
|
|
else p.plugin.rtp
|
|
|
|
}
|
|
|
|
'') cfg.plugins)}
|
|
|
|
# ============================================= #
|
|
|
|
'';
|
|
|
|
};
|
2018-09-14 16:14:39 +00:00
|
|
|
in
|
|
|
|
|
|
|
|
{
|
|
|
|
options = {
|
|
|
|
programs.tmux = {
|
2019-02-10 01:19:56 +00:00
|
|
|
aggressiveResize = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
|
|
|
Resize the window to the size of the smallest session for
|
|
|
|
which it is the current window.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
baseIndex = mkOption {
|
|
|
|
default = 0;
|
|
|
|
example = 1;
|
|
|
|
type = types.ints.unsigned;
|
|
|
|
description = "Base index for windows and panes.";
|
|
|
|
};
|
|
|
|
|
|
|
|
clock24 = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = "Use 24 hour clock.";
|
|
|
|
};
|
|
|
|
|
|
|
|
customPaneNavigationAndResize = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
|
|
|
Override the hjkl and HJKL bindings for pane navigation and
|
|
|
|
resizing in VI mode.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2019-06-04 11:21:20 +00:00
|
|
|
disableConfirmationPrompt = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
|
|
|
Disable confirmation prompt before killing a pane or window
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-09-14 16:14:39 +00:00
|
|
|
enable = mkEnableOption "tmux";
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
escapeTime = mkOption {
|
|
|
|
default = 500;
|
|
|
|
example = 0;
|
|
|
|
type = types.ints.unsigned;
|
|
|
|
description = ''
|
|
|
|
Time in milliseconds for which tmux waits after an escape is
|
|
|
|
input.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
extraConfig = mkOption {
|
|
|
|
type = types.lines;
|
|
|
|
default = "";
|
|
|
|
description = ''
|
|
|
|
Additional configuration to add to
|
|
|
|
<filename>tmux.conf</filename>.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
historyLimit = mkOption {
|
|
|
|
default = 2000;
|
|
|
|
example = 5000;
|
|
|
|
type = types.ints.positive;
|
|
|
|
description = "Maximum number of lines held in window history.";
|
|
|
|
};
|
|
|
|
|
|
|
|
keyMode = mkOption {
|
|
|
|
default = defaultKeyMode;
|
|
|
|
example = "vi";
|
|
|
|
type = types.enum [ "emacs" "vi" ];
|
|
|
|
description = "VI or Emacs style shortcuts.";
|
|
|
|
};
|
|
|
|
|
|
|
|
newSession = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
|
|
|
Automatically spawn a session if trying to attach and none
|
|
|
|
are running.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-09-14 16:14:39 +00:00
|
|
|
package = mkOption {
|
|
|
|
type = types.package;
|
|
|
|
default = pkgs.tmux;
|
2019-08-27 22:12:28 +00:00
|
|
|
defaultText = literalExample "pkgs.tmux";
|
2018-09-14 16:14:39 +00:00
|
|
|
example = literalExample "pkgs.tmux";
|
|
|
|
description = "The tmux package to install";
|
|
|
|
};
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
reverseSplit = mkOption {
|
|
|
|
default = false;
|
|
|
|
type = types.bool;
|
|
|
|
description = "Reverse the window split shortcuts.";
|
|
|
|
};
|
|
|
|
|
|
|
|
resizeAmount = mkOption {
|
|
|
|
default = defaultResize;
|
|
|
|
example = 10;
|
|
|
|
type = types.ints.positive;
|
|
|
|
description = "Number of lines/columns when resizing.";
|
|
|
|
};
|
|
|
|
|
2018-09-14 16:14:39 +00:00
|
|
|
sensibleOnTop = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = ''
|
|
|
|
Run the sensible plugin at the top of the configuration. It
|
|
|
|
is possible to override the sensible settings using the
|
|
|
|
<option>programs.tmux.extraConfig</option> option.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2020-05-20 13:23:00 +00:00
|
|
|
prefix = mkOption {
|
|
|
|
default = null;
|
|
|
|
example = "C-a";
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
description = ''
|
|
|
|
Set the prefix key. Overrules the "shortcut" option when set.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
shortcut = mkOption {
|
|
|
|
default = defaultShortcut;
|
|
|
|
example = "a";
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
CTRL following by this key is used as the main shortcut.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
|
|
|
terminal = mkOption {
|
|
|
|
default = defaultTerminal;
|
|
|
|
example = "screen-256color";
|
|
|
|
type = types.str;
|
|
|
|
description = "Set the $TERM variable.";
|
|
|
|
};
|
|
|
|
|
2019-10-15 02:23:32 +00:00
|
|
|
shell = mkOption {
|
|
|
|
default = defaultShell;
|
|
|
|
example = "\${pkgs.zsh}/bin/zsh";
|
|
|
|
type = with types; nullOr str;
|
|
|
|
description = "Set the default-shell tmux variable.";
|
|
|
|
};
|
|
|
|
|
2019-02-10 01:19:56 +00:00
|
|
|
secureSocket = mkOption {
|
2020-06-21 09:20:00 +00:00
|
|
|
default = pkgs.stdenv.isLinux;
|
2019-02-10 01:19:56 +00:00
|
|
|
type = types.bool;
|
|
|
|
description = ''
|
|
|
|
Store tmux socket under <filename>/run</filename>, which is more
|
|
|
|
secure than <filename>/tmp</filename>, but as a downside it doesn't
|
|
|
|
survive user logout.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
|
2018-09-14 16:14:39 +00:00
|
|
|
tmuxp.enable = mkEnableOption "tmuxp";
|
|
|
|
|
|
|
|
tmuxinator.enable = mkEnableOption "tmuxinator";
|
|
|
|
|
|
|
|
plugins = mkOption {
|
|
|
|
type = with types;
|
|
|
|
listOf (either package pluginModule)
|
|
|
|
// { description = "list of plugin packages or submodules"; };
|
|
|
|
description = ''
|
|
|
|
List of tmux plugins to be included at the end of your tmux
|
|
|
|
configuration. The sensible plugin, however, is defaulted to
|
|
|
|
run at the top of your configuration.
|
|
|
|
'';
|
|
|
|
default = [ ];
|
|
|
|
example = literalExample ''
|
|
|
|
with pkgs; [
|
|
|
|
tmuxPlugins.cpu
|
|
|
|
{
|
|
|
|
plugin = tmuxPlugins.resurrect;
|
|
|
|
extraConfig = "set -g @resurrect-strategy-nvim 'session'";
|
|
|
|
}
|
|
|
|
{
|
|
|
|
plugin = tmuxPlugins.continuum;
|
|
|
|
extraConfig = '''
|
|
|
|
set -g @continuum-restore 'on'
|
|
|
|
set -g @continuum-save-interval '60' # minutes
|
|
|
|
''';
|
|
|
|
}
|
|
|
|
]
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable (
|
2020-04-25 15:02:49 +00:00
|
|
|
mkMerge ([
|
2018-09-14 16:14:39 +00:00
|
|
|
{
|
|
|
|
home.packages = [ cfg.package ]
|
|
|
|
++ optional cfg.tmuxinator.enable pkgs.tmuxinator
|
|
|
|
++ optional cfg.tmuxp.enable pkgs.tmuxp;
|
|
|
|
}
|
2019-04-04 22:04:24 +00:00
|
|
|
(mkIf cfg.secureSocket {
|
|
|
|
home.sessionVariables = {
|
|
|
|
TMUX_TMPDIR = ''''${XDG_RUNTIME_DIR:-"/run/user/\$(id -u)"}'';
|
|
|
|
};
|
|
|
|
})
|
|
|
|
|
2021-04-23 07:25:13 +00:00
|
|
|
{ xdg.configFile."tmux/tmux.conf".text = mkBefore tmuxConf; }
|
2020-04-25 15:02:49 +00:00
|
|
|
(mkIf (cfg.plugins != []) configPlugins)
|
2021-04-23 07:25:13 +00:00
|
|
|
{ xdg.configFile."tmux/tmux.conf".text = mkAfter cfg.extraConfig; }
|
2020-04-25 15:02:49 +00:00
|
|
|
])
|
2018-09-14 16:14:39 +00:00
|
|
|
);
|
|
|
|
}
|