diff --git a/ansible/dotfiles.yml b/ansible/dotfiles.yml index 3270da9..9f1ba78 100644 --- a/ansible/dotfiles.yml +++ b/ansible/dotfiles.yml @@ -52,6 +52,12 @@ tags: - agents + - name: Include tmux setup tasks + include_tasks: tasks/tmux.yml + tags: + - tmux + - setup + - name: Include dotfile linking tasks include_tasks: tasks/link_files.yml tags: diff --git a/ansible/tasks/link_files.yml b/ansible/tasks/link_files.yml index f02572c..ccd0960 100644 --- a/ansible/tasks/link_files.yml +++ b/ansible/tasks/link_files.yml @@ -40,6 +40,7 @@ - { src: "github/create_pr.bash", dest: ".bin/pr" } - { src: "hammerspoon/init.lua", dest: ".hammerspoon/init.lua" } - { src: "ghostty/config", dest: ".config/ghostty/config" } + - { src: "tmux/tmux.conf", dest: ".tmux.conf" } - { src: "python/scratch_python_project.sh", dest: ".bin/scratch_python_project", diff --git a/ansible/tasks/tmux.yml b/ansible/tasks/tmux.yml new file mode 100644 index 0000000..d40f8b0 --- /dev/null +++ b/ansible/tasks/tmux.yml @@ -0,0 +1,12 @@ +--- +- name: Clone TPM (Tmux Plugin Manager) + ansible.builtin.git: + repo: https://github.com/tmux-plugins/tpm + dest: "{{ ansible_user_dir }}/.tmux/plugins/tpm" + depth: 1 + +- name: Install tmux plugins via TPM + ansible.builtin.command: + cmd: "{{ ansible_user_dir }}/.tmux/plugins/tpm/bin/install_plugins" + environment: + TMUX_PLUGIN_MANAGER_PATH: "{{ ansible_user_dir }}/.tmux/plugins" diff --git a/fish/config.fish b/fish/config.fish index e30e007..b24e78e 100644 --- a/fish/config.fish +++ b/fish/config.fish @@ -20,6 +20,11 @@ if test "$TERM_PROGRAM" = vscode exit 0 end +# Auto-attach to tmux in Ghostty (but not inside nvim, scripts, or existing tmux) +if test "$TERM_PROGRAM" = ghostty; and not set -q TMUX; and not set -q NVIM; and status is-interactive + tmux new-session -A -s main +end + # Initialize starship and zoxide starship init fish | source zoxide init fish | source diff --git a/ghostty/config b/ghostty/config index 47b98bb..e0a9a88 100644 --- a/ghostty/config +++ b/ghostty/config @@ -4,3 +4,7 @@ font-size = 16 shell-integration = fish theme = Catppuccin Frappe command = /opt/homebrew/bin/fish + +# Let tmux handle all window/tab management +keybind = super+t=unbind +keybind = super+n=unbind diff --git a/nvim/lua/plugins/tmux-navigator.lua b/nvim/lua/plugins/tmux-navigator.lua new file mode 100644 index 0000000..688b62e --- /dev/null +++ b/nvim/lua/plugins/tmux-navigator.lua @@ -0,0 +1,16 @@ +return { + "christoomey/vim-tmux-navigator", + cmd = { + "TmuxNavigateLeft", + "TmuxNavigateDown", + "TmuxNavigateUp", + "TmuxNavigateRight", + "TmuxNavigatePrevious", + }, + keys = { + { "", "TmuxNavigateLeft", desc = "Navigate left" }, + { "", "TmuxNavigateDown", desc = "Navigate down" }, + { "", "TmuxNavigateUp", desc = "Navigate up" }, + { "", "TmuxNavigateRight", desc = "Navigate right" }, + }, +} diff --git a/nvim/lua/plugins/toggleterm.lua b/nvim/lua/plugins/toggleterm.lua index 0cd8803..455160b 100644 --- a/nvim/lua/plugins/toggleterm.lua +++ b/nvim/lua/plugins/toggleterm.lua @@ -78,10 +78,10 @@ return { local opts = { buffer = 0 } vim.keymap.set("t", "", [[]], opts) vim.keymap.set("t", "jk", [[]], opts) - vim.keymap.set("t", "", [[wincmd h]], opts) - vim.keymap.set("t", "", [[wincmd j]], opts) - vim.keymap.set("t", "", [[wincmd k]], opts) - vim.keymap.set("t", "", [[wincmd l]], opts) + vim.keymap.set("t", "", [[TmuxNavigateLeft]], opts) + vim.keymap.set("t", "", [[TmuxNavigateDown]], opts) + vim.keymap.set("t", "", [[TmuxNavigateUp]], opts) + vim.keymap.set("t", "", [[TmuxNavigateRight]], opts) vim.keymap.set("t", "", [[]], opts) end diff --git a/tmux/cheatsheet.md b/tmux/cheatsheet.md new file mode 100644 index 0000000..5d8b30c --- /dev/null +++ b/tmux/cheatsheet.md @@ -0,0 +1,57 @@ +# Ghostty + tmux Cheatsheet + +Prefix key: `Ctrl-a` + +All window and tab management is handled by tmux. Ghostty's `Cmd-T` and +`Cmd-N` are unbound to avoid conflicts. + +## tmux (prefix = Ctrl-a) + +### Sessions + +| Keys | Action | +| --- | --- | +| `prefix d` | Detach from session | +| `prefix s` | List / switch sessions | +| `prefix $` | Rename session | +| `tmux new -s name` | New named session | + +### Windows (tabs inside tmux) + +| Keys | Action | +| --- | --- | +| `prefix c` | New window | +| `prefix ,` | Rename window | +| `prefix n` / `prefix p` | Next / previous window | +| `prefix 1-9` | Jump to window by number | +| `prefix Ctrl-a` | Toggle last window | +| `prefix &` | Kill window | + +### Panes (splits inside a window) + +| Keys | Action | +| --- | --- | +| `prefix i` | Split horizontal | +| `prefix u` | Split vertical | +| `Ctrl-h/j/k/l` | Navigate panes (vim-tmux-navigator) | +| `prefix z` | Zoom / unzoom pane | +| `prefix x` | Kill pane | +| `prefix Space` | Enter copy mode (vi keys) | + +### Copy mode (vi) + +| Keys | Action | +| --- | --- | +| `/` | Search forward | +| `?` | Search backward | +| `v` | Begin selection | +| `y` | Yank selection | +| `q` | Exit copy mode | + +## Ghostty + +| Keys | Action | +| --- | --- | +| `Cmd-+` / `Cmd--` | Zoom in / out | +| `Cmd-Shift-,` | Open config | +| `Cmd-K` | Clear screen | diff --git a/tmux/tmux.conf b/tmux/tmux.conf new file mode 100644 index 0000000..f6fafdd --- /dev/null +++ b/tmux/tmux.conf @@ -0,0 +1,67 @@ +#{{{1 GENERAL OPTIONS + +set-option -g default-shell "/opt/homebrew/bin/fish" +set-option -g default-terminal "tmux-256color" +set-option -ga terminal-overrides ",xterm-ghostty:Tc" +set-option -g history-limit 100000 +set-option -g focus-events on +set-option -g escape-time 0 +set-option -g mouse on + +#{{{1 KEY BINDS + +#{{{2 UNBINDS + +unbind C-b +unbind l +unbind h +unbind k +unbind j +unbind u +unbind i +unbind Space + +#{{{2 GENERAL + +set -g prefix C-a +bind-key a send-prefix +bind r source-file ~/.tmux.conf \; display-message "Config reloaded..." +bind Space copy-mode +set-window-option -g mode-keys vi + +#{{{2 WINDOWS + +bind-key C-a last-window + +#{{{2 PANES + +# Splits +bind u split-window -v -c "#{pane_current_path}" +bind i split-window -h -c "#{pane_current_path}" + +# Vim-tmux-navigator handles C-h/j/k/l pane switching +# See: https://github.com/christoomey/vim-tmux-navigator + +#{{{1 WINDOW SETTINGS + +set -g base-index 1 +set-window-option -g pane-base-index 1 +set -g renumber-windows on +set-window-option -g automatic-rename on +set-option -g allow-rename off +set -g set-titles on + +#{{{1 PLUGINS (TPM) + +set -g @plugin 'tmux-plugins/tpm' +set -g @plugin 'christoomey/vim-tmux-navigator' +set -g @plugin 'catppuccin/tmux' + +#{{{2 CATPPUCCIN + +set -g @catppuccin_flavor 'frappe' + +#{{{1 INITIALIZE TPM +# (keep this line at the very bottom of tmux.conf) + +run '~/.tmux/plugins/tpm/tpm'