├── LICENSE ├── README.md ├── active-row.conf ├── demo.gif ├── inactive-row.conf └── new-tmux /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Alessandro Di Federico 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nested tmux 2 | 3 | This is a simple tmux configuration enabling to have arbitrarily many nested tmux sessions. 4 | 5 | # Demo 6 | 7 | ![Demo](/demo.gif?raw=true "Demo") 8 | 9 | # Quick start 10 | 11 | ``` 12 | mkdir ~/.tmux.conf.d/ 13 | cd ~/.tmux.conf.d/ 14 | git clone https://github.com/aleclearmind/nested-tmux.git 15 | mv ~/.tmux.conf ~/.tmux.conf.backup 16 | echo "source ~/.tmux.conf.d/nested-tmux/active-row.conf" > ~/.tmux.conf 17 | tmux 18 | ``` 19 | 20 | # Shortcuts 21 | 22 | * `Ctrl + a, Ctrl + c` or `Ctrl + t`: create a new window 23 | * `Ctrl + a, Ctrl + s`: create a new nested tmux session and ask a name for it 24 | * `Ctrl + a, Ctrl + A`: switch to last window 25 | * `Ctrl + a, A`: rename current window 26 | * `Alt + Right`: move to the next window of the current row 27 | * `Alt + Left`: move to the previous window of the current row 28 | * `Alt + Up`: move to the inner tmux session 29 | * `Alt + Down`: move to the outer tmux session 30 | 31 | # FAQ 32 | 33 | * **Q**: Why do we need this? 34 | 35 | **A**: When working with many projects it's useful to have a dedicated tmux session with three windows per-project: one with a text editor, one for git and one for the build directory. 36 | This is why this project was born. 37 | However, nested tmux sessions are addictive and quickly become in-terminal *workspaces* that can be used for any purpose. 38 | 39 | * **Q**: Does it support multiple nested layers of tmux sessions? 40 | 41 | **A**: Yes. 42 | 43 | * **Q**: Has it been tested with other configuration X? 44 | 45 | **A**: No. 46 | 47 | * **Q**: How is this implemented? 48 | 49 | **A**: The idea is two have two configurations, `active-row.conf` and `inactive-row.conf`. 50 | The former is for the currently active row in the nested tmux tree, the second for the inactive rows. 51 | Each session know who its parent is through the `TMUX_PARENT` environment variable (set in the `new-tmux` script). 52 | When `Alt + Up` is pressed, the `Alt + F12` combination is sent to the active window. 53 | If the active window is a nested tmux session, it will load `active-row.conf` and forces loading `inactive-row.conf` in its parent (i.e., the row that originally received the `Alt + Up` key combination. 54 | When `Alt + Down` is pressed, the current row loads `inactive-row.conf` and forces loading `active-row.conf` in its parent. 55 | -------------------------------------------------------------------------------- /active-row.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Colors 3 | # 4 | active_window_bg=colour34 5 | inactive_window_bg=colour102 6 | bar_bg=colour237 7 | bar_fg=colour255 8 | 9 | # 10 | # General settings 11 | # 12 | set -g default-terminal screen.xterm-256color 13 | set -g status-right '' 14 | set -g status-left '' 15 | set -g history-limit 100000 16 | 17 | # 18 | # Configure prefix 19 | # 20 | unbind C-b 21 | set -g prefix C-a 22 | 23 | # 24 | # Prefixed commands 25 | # 26 | 27 | # Create a new window (Ctrl + A, Ctrl + c) 28 | bind C-c new-window 29 | 30 | # Create a new nested tmux (Ctrl + A, Ctrl + s) 31 | bind C-s new-window ~/.tmux.conf.d/nested-tmux/new-tmux \; \ 32 | rename-window '' \; \ 33 | command-prompt -I "#W" "rename-window -- '%%'" 34 | 35 | # Switch to last window (Ctrl + A, Ctrl + A) 36 | bind C-a last-window 37 | 38 | # Rename current window (Ctrl + A, A) 39 | bind A rename-window '' \; \ 40 | command-prompt -I "#W" "rename-window -- '%%'" 41 | 42 | # Enable search mode 43 | bind -T copy-mode -n / command-prompt -i -I "#{pane_search_string}" -p "(search down)" "send -X search-forward-incremental \"%%%\"" 44 | 45 | # 46 | # Non-prefixed commands 47 | # 48 | 49 | # Go to next window (Alt + Right) 50 | bind -n M-right next 51 | 52 | # Go to previous window (Alt + Left) 53 | bind -n M-left prev 54 | 55 | # Create new window (Ctrl + t) 56 | bind -n C-t new-window 57 | 58 | # Switch to inner tmux (Alt + Up) 59 | bind -n M-up send-keys M-F12 60 | 61 | # Switch to outer tmux (Alt + Down) 62 | bind -n M-down source-file ~/.tmux.conf.d/nested-tmux/inactive-row.conf \; \ 63 | run-shell 'tmux -L $TMUX_PARENT source-file ~/.tmux.conf.d/nested-tmux/active-row.conf' \; \ 64 | run-shell 'tmux -L $TMUX_PARENT set -g window-status-current-style bg=$active_window_bg' 65 | 66 | # Handler for becoming active (Alt + F12, don't use directly) 67 | bind -n M-F12 run-shell 'tmux -L $TMUX_PARENT source-file ~/.tmux.conf.d/nested-tmux/inactive-row.conf' \; \ 68 | source-file ~/.tmux.conf.d/nested-tmux/active-row.conf \; \ 69 | set -g window-status-current-style bg=$active_window_bg 70 | 71 | # Handler for closed window: enable outer terminal 72 | set-hook -g client-detached "run-shell 'tmux -L $TMUX_PARENT source-file ~/.tmux.conf.d/nested-tmux/active-row.conf && tmux -L $TMUX_PARENT set -g window-status-current-style bg=$active_window_bg'" 73 | 74 | # 75 | # Appearance 76 | # 77 | set -g status-style bg=$bar_bg 78 | setw -g window-status-style fg=$bar_fg 79 | setw -g window-status-current-format ' #I #W ' 80 | setw -g window-status-format ' #I #W ' 81 | setw -g window-status-current-style bg=$active_window_bg 82 | 83 | # If we're the root tmux, unbind M-down 84 | if-shell 'test -z "$TMUX_PARENT"' 'bind -n M-down send-keys ""' '' 85 | 86 | # When a new session is created unbind the parent 87 | if-shell 'test -z "$TMUX_PARENT"' '' 'run-shell "tmux -L $TMUX_PARENT source-file ~/.tmux.conf.d/nested-tmux/inactive-row.conf"' 88 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aleclearmind/nested-tmux/58c69f93d1039cee074b60b216bbcced9262196b/demo.gif -------------------------------------------------------------------------------- /inactive-row.conf: -------------------------------------------------------------------------------- 1 | # Change the background color to unactive 2 | setw -g window-status-current-style bg=$inactive_window_bg 3 | 4 | # Unbind prefix 5 | set -u -g prefix C-a 6 | 7 | # Unbind each unprefixed command 8 | unbind -n M-left 9 | unbind -n M-right 10 | unbind -n M-up 11 | unbind -n M-down 12 | unbind -n C-t 13 | -------------------------------------------------------------------------------- /new-tmux: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TMUX_PARENT=$(basename "$TMUX") 4 | TMUX_PARENT="${TMUX_PARENT%%,*}" 5 | export TMUX_PARENT 6 | 7 | tmux -L "r$RANDOM" 8 | --------------------------------------------------------------------------------