diff --git a/lib/shared/home-manager-packages.nix b/lib/shared/home-manager-packages.nix index 307eeef..daa54dc 100644 --- a/lib/shared/home-manager-packages.nix +++ b/lib/shared/home-manager-packages.nix @@ -20,6 +20,7 @@ let ); notetaker = writeShellApplication (import ./scripts/notetaker.nix); run = writeShellApplication (import ./scripts/run.nix { inherit pkgs; }); + t = writeShellApplication (import ./scripts/t.nix { inherit pkgs; }); timer = writeShellApplication (import ./scripts/timer.nix); in with pkgs; diff --git a/lib/shared/home-manager.nix b/lib/shared/home-manager.nix index 3a56f5f..4172369 100644 --- a/lib/shared/home-manager.nix +++ b/lib/shared/home-manager.nix @@ -30,6 +30,7 @@ in ./modules/phpactor.nix ./modules/ripgrep.nix ./modules/syncthing.nix + ./modules/tmux.nix ./modules/zellij.nix ./modules/zsh.nix ]; diff --git a/lib/shared/modules/tmux.nix b/lib/shared/modules/tmux.nix new file mode 100644 index 0000000..bbfc1c2 --- /dev/null +++ b/lib/shared/modules/tmux.nix @@ -0,0 +1,82 @@ +{ pkgs, ... }: +let + inherit (pkgs) tmuxPlugins; +in +{ + programs.tmux = { + enable = true; + + terminal = "tmux-256color"; + + extraConfig = '' + set-option -g status-keys "vi" + set-option -sa terminal-features "''${TERM}:RGB" + + bind -n S-Left resize-pane -L 2 + bind -n S-Right resize-pane -R 2 + bind -n S-Down resize-pane -D 1 + bind -n S-Up resize-pane -U 1 + + bind -n C-Left resize-pane -L 10 + bind -n C-Right resize-pane -R 10 + bind -n C-Down resize-pane -D 5 + bind -n C-Up resize-pane -U 5 + + # Status line customisation + set-option -g status-left "" + set-option -g status-right " #{session_name}" + set-option -g status-right-length 100 + set-option -g status-style "fg=#7C7D83 bg=default" + set-option -g window-status-activity-style none + set-option -g window-status-current-format "#{window_index}:#{pane_current_command}#{window_flags} " + set-option -g window-status-current-style "fg=#E9E9EA" + set-option -g window-status-format "#{window_index}:#{pane_current_command}#{window_flags} " + + bind c new-window -c "#{pane_current_path}" + + set -g base-index 1 + set -g pane-base-index 1 + set -g renumber-windows on + + # Break a pane into a new window. + bind-key b break-pane -d + bind-key J command-prompt -p "join pane from: " "join-pane -h -s '%%'" + + bind-key C-j choose-tree + + # Use vim keybindings in copy mode + setw -g mode-keys vi + + # Setup 'v' to begin selection as in Vim + bind-key -T copy-mode-vi 'v' send -X begin-selection + bind-key -T copy-mode-vi 'y' send -X copy-pipe wl-copy + + bind C-j split-window -v "tmux list-sessions | sed -E 's/:.*$//' | grep -v \"^$(tmux display-message -p '#S')\$\" | fzf --reverse | xargs tmux switch-client -t" + + bind-key K run-shell 'tmux switch-client -n \; kill-session -t "$(tmux display-message -p "#S")" || tmux kill-session' + + # Allow clearing screen with ctrl-l by using C-l + bind C-l send-keys "C-l" + bind C-k send-keys "C-k" + + # Enable mouse support. + setw -g mouse on + + # Remove delay when switching Vim modes. + set -sg escape-time 0 + + set-option -g pane-active-border-style "fg=#1f2335" + set-option -g pane-border-style "fg=#1f2335" + + bind-key -r f run-shell "tmux new-window t" + + set -g @resurrect-strategy-nvim 'session' + ''; + + plugins = [ + tmuxPlugins.resurrect + tmuxPlugins.vim-tmux-navigator + tmuxPlugins.yank + ]; + }; +} diff --git a/lib/shared/modules/zsh/abbreviations.zsh b/lib/shared/modules/zsh/abbreviations.zsh index 5b0edde..82f2667 100644 --- a/lib/shared/modules/zsh/abbreviations.zsh +++ b/lib/shared/modules/zsh/abbreviations.zsh @@ -32,6 +32,11 @@ abbr gs="git status" abbr gsh="git show" abbr gst="git status" +# tmux +abbr ta="tmux attach" +abbr tl="tmux list-sessions" +abbr tk="tmux kill-session" + # zellij abbr czs="create-zellij-session" abbr z="zellij" diff --git a/lib/shared/scripts/t.nix b/lib/shared/scripts/t.nix new file mode 100644 index 0000000..d9f91e3 --- /dev/null +++ b/lib/shared/scripts/t.nix @@ -0,0 +1,86 @@ +{ pkgs }: + +{ + name = "t"; + + runtimeInputs = with pkgs; [ + openssl + tmux + ]; + + text = '' + # Credit to ThePrimeagen and Jess Archer. + + function execute_tmux_file { + local tmux_file="$1" + selected_path="$2" + session_name="$3" + + DIGEST="$(openssl sha512 "$tmux_file")" + + # Prompt the first time we see a given .tmux file before running it. + if ! grep -q "$DIGEST" ~/..tmux.digests 2> /dev/null; then + cat "$tmux_file" + + read -r -n 1 -p "Trust (and run) this .tmux file? (t = trust, otherwise = skip) " + + if [[ $REPLY =~ ^[Tt]$ ]]; then + echo "$DIGEST" >> ~/..tmux.digests + + create_session_and_run_tmux_file "$tmux_file" "$selected_path" "$session_name" + fi + else + create_session_and_run_tmux_file "$tmux_file" "$selected_path" "$session_name" + fi + } + + function create_session_and_run_tmux_file { + tmux_file="$1" + selected_path="$2" + session_name="$3" + + tmux new-session -d -c "$selected_path" -s "$session_name" + (cd "$selected_path" && "$tmux_file" "$session_name") + } + + function main { + if [[ $# -eq 1 ]]; then + selected_path=$1 + else + # Get the session name from fuzzy-finding list of directories and generating a + # tmux-safe version. + items=$(find "$REPOS" ~/Documents \ + -maxdepth 1 -mindepth 1 -type d \ + ! -name "_archive" \ + ! -name "*-old" \ + ! -name "*.old" + ) + + selected_path=$(echo "''${items}" | sort | fzf --reverse) + fi + + session_name=$(basename "$selected_path" | sed 's/\./_/g') + + # Attach to an existing session, if one exists. + if tmux has-session -t "$session_name" 2> /dev/null; then + tmux attach -t "$session_name" || tmux switch-client -t "$session_name" + exit + fi + + if [[ -x "$selected_path/.tmux" ]]; then + execute_tmux_file "$selected_path/.tmux" "$selected_path" "$session_name" + elif [[ -x "$selected_path/.ignored/.tmux" ]]; then + execute_tmux_file "$selected_path/.ignored/.tmux" "$selected_path" "$session_name" + fi + + # If there is no session, create one. + if ! tmux has-session -t "$session_name" 2> /dev/null; then + tmux new-session -d -c "$selected_path" -s "$session_name" + fi + + tmux switch-client -t "$session_name" 2>/dev/null || tmux attach-session -t "$session_name" + } + + main "$@" + ''; +}