- Authors
- Name
- 1. はじめに:なぜVim + Tmuxなのか
- 2. ゼロから始める:環境構築
- 3. 【戦略1】シームレスなナビゲーション -- vim-tmux-navigator
- 4. 【戦略2】直感的なパネル分割 -- 視覚メタファーマッピング
- 5. 【戦略3】Vimux -- 超高速フィードバックループ
- 6. 【戦略4】システムクリップボード同期
- 7. 【戦略5】Dotfilesと開発者アイデンティティ
- 8. 完全な設定ファイル(コピー&ペースト対応)
- 9. 生産性の測定:ワークフロー比較
- 10. トラブルシューティングとFAQ
- 11. まとめ:最小抵抗の道
- 12. 参考文献
- クイズ
1. はじめに:なぜVim + Tmuxなのか
1.1 コンテキストスイッチの見えないコスト
開発者の典型的な1日を思い浮かべてみてください。コードを書き、ターミナルに切り替え、テストを実行し、ブラウザにジャンプして、再びエディタに戻る。この過程で手がマウスに伸びるたびに、コンテキストスイッチが発生します。認知科学の研究によると、1回のコンテキストスイッチの後、元の集中状態に戻るまで平均23分かかります(カリフォルニア大学アーバイン校の研究)。ウィンドウ切り替えのようなマイクロスイッチが丸々23分かかるわけではありませんが、1日に何百回も繰り返されると、その累積コストは決して無視できません。
問題の本質はツール間の継ぎ目にあります。IDEからターミナルへ、ターミナルからブラウザへ、ブラウザからメモアプリへ — それぞれの遷移で手がキーボードからマウスへ移動し、注意が散漫になり、思考の流れが途切れます。
1.2 統合開発環境という答え
VimとTmuxの組み合わせは、この問題に根本的な答えを提示します。
┌─────────────────────────────────────────────────────────────┐
│ Terminal Emulator (Ghostty) │
│ ┌──────────────────────────┬──────────────────────────────┐ │
│ │ │ │ │
│ │ Vim/Neovim (Code) │ Tmux Pane (Server Log) │ │
│ │ │ │ │
│ │ - File browsing │ $ tail -f app.log │ │
│ │ - Code editing │ │ │
│ │ - LSP autocomplete │ │ │
│ │ │ │ │
│ ├──────────────────────────┤ │ │
│ │ │ │ │
│ │ Vimux (Test runner) │ │ │
│ │ │ │ │
│ │ $ pytest -v tests/ │ │ │
│ │ ✓ 12 passed │ │ │
│ │ │ │ │
│ └──────────────────────────┴──────────────────────────────┘ │
│ [0] dev* [1] server [2] db youngjukim 15:42 │
└─────────────────────────────────────────────────────────────┘
上の図が示すように、VimとTmuxを組み合わせることで、コード編集、テスト実行、ログ監視、サーバー管理のすべてが1つのターミナル内に収まります。マウスなしで、キーボードだけで、思考の速度であらゆる作業を遂行できます。
1.3 キーボード中心ワークフローの哲学
VimとTmuxが共有する核心の哲学は、**「最小抵抗の道」**です。
| パラダイム | GUI中心ワークフロー | Vim + Tmuxワークフロー |
|---|---|---|
| ウィンドウ切り替え | Alt-Tab / Cmd-Tab + マウスクリック | Ctrl-h/j/k/l 即座に移動 |
| ファイル検索 | マウスでフォルダツリーをクリック | :Telescope find_files / fzf |
| テスト実行 | ターミナルに切り替えてコマンド入力 | <Leader>tt 一発 |
| テキストコピー | マウスドラッグ→Ctrl-C | yy(Vimヤンクからシステムクリップボードへ) |
| 環境復元 | アプリ再起動、ウィンドウ再配置 | tmux attach(セッション復元) |
この記事では、VimとTmuxを真に統合された環境に変える5つの核心戦略を取り上げます。各戦略にはすぐに使える設定ファイルと実践例が含まれています。
1.4 この記事の前提条件
この記事を最大限に活用するには、以下の環境が整っていることが望ましいです。
# バージョン確認
vim --version | head -1 # Vim 9.0+ または
nvim --version | head -1 # Neovim 0.10+
tmux -V # tmux 3.3+
git --version # Git 2.40+
Vimのモーション(h/j/k/l、w/b/e、dd/yy/p)とTmuxの基本(セッション、ウィンドウ、ペイン)の基礎的な理解を前提としています。Tmuxの入門が必要な場合は、まずTmuxコマンド完全ガイドを参照してください。
2. ゼロから始める:環境構築
戦略に入る前に、完全に新しいマシンからVim + Tmux開発環境を構築する手順を説明します。
2.1 ターミナルエミュレータのインストール:Ghostty
GhosttyはZigで書かれたGPUアクセラレーション対応のターミナルエミュレータで、macOSではMetal、LinuxではOpenGLを使用します。2025年の一般公開以来、コミュニティから急速に注目を集めています。ネイティブUIコンポーネントを使用してプラットフォームとシームレスに統合し、Nerd Fontsをデフォルトでサポートし、Kitty Graphics Protocolによるターミナル内画像レンダリングを可能にします。
# macOS (Homebrew)
brew install --cask ghostty
# Linux(ソースからのビルドが必要な場合あり — 公式パッケージを確認)
# https://ghostty.org/docs
Ghostty設定ファイル(~/.config/ghostty/config):
# ~/.config/ghostty/config
font-family = Monaspace Neon
font-size = 14
font-feature = calt
font-feature = liga
font-feature = ss01
font-feature = ss02
font-feature = ss03
font-feature = ss09
theme = catppuccin-mocha
cursor-style = block
cursor-style-blink = false
shell-integration = zsh
window-padding-x = 8
window-padding-y = 4
window-decoration = true
# Tmuxと併用する場合 — Ghostty独自のタブ/分割よりTmuxを優先
keybind = super+t=unbind
2.2 フォントのインストール:Monaspace
MonaspaceはGitHub Nextが開発した等幅フォントスーパーファミリーで、5つの書体(Neon、Argon、Xenon、Radon、Krypton)、Texture Healingテクノロジー、10グループのコーディング合字を特徴とします。
# macOS
brew tap homebrew/cask-fonts
brew install font-monaspace
# Linux — 手動インストール
mkdir -p ~/.local/share/fonts
cd /tmp
wget https://github.com/githubnext/monaspace/releases/latest/download/monaspace-v1.101.zip
unzip monaspace-v1.101.zip -d monaspace
cp monaspace/monaspace-v1.101/fonts/otf/*.otf ~/.local/share/fonts/
fc-cache -fv
# Nerd Fontパッチ版(アイコンが必要な場合)
brew install font-monaspace-nerd-font # macOS
2.3 Neovimのインストール
# macOS
brew install neovim
# Ubuntu / Debian(最新バージョン)
sudo add-apt-repository ppa:neovim-ppa/unstable
sudo apt update && sudo apt install -y neovim
# Arch Linux
sudo pacman -S neovim
# AppImage(ユニバーサル)
curl -LO https://github.com/neovim/neovim/releases/latest/download/nvim.appimage
chmod u+x nvim.appimage
sudo mv nvim.appimage /usr/local/bin/nvim
2.4 TmuxのインストールとTPM(Tmux Plugin Manager)のセットアップ
# macOS
brew install tmux
# Ubuntu / Debian
sudo apt install -y tmux
# TPMのインストール
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm
TPMをインストールした後、Tmux内でprefix + I(大文字のI)を押すとプラグインが自動インストールされます。
2.5 Neovim Kickstartで始める
Kickstart.nvimはNeovimのディストリビューションではなく、独自の設定を構築するための教育的な出発点です。単一のinit.luaファイルで構成されており、すべての設定を一目で理解できます。
# 既存の設定をバックアップ(ある場合)
mv ~/.config/nvim{,.bak}
mv ~/.local/share/nvim{,.bak}
mv ~/.local/state/nvim{,.bak}
mv ~/.cache/nvim{,.bak}
# Kickstartをクローン
git clone https://github.com/nvim-lua/kickstart.nvim.git ~/.config/nvim
# Neovimを起動 — プラグインが自動的にインストールされる
nvim
Kickstartにはデフォルトで以下が含まれています:
- lazy.nvim -- プラグインマネージャ
- telescope.nvim -- ファジーファインダー
- treesitter -- シンタックスハイライト
- LSP -- Language Server Protocolサポート
- nvim-cmp -- 自動補完
- which-key -- キーバインドのディスカバリ
2.6 Starshipプロンプトのインストール
# インストール
curl -sS https://starship.rs/install.sh | sh
# ~/.zshrcに追加
echo 'eval "$(starship init zsh)"' >> ~/.zshrc
# または~/.bashrcに追加
echo 'eval "$(starship init bash)"' >> ~/.bashrc
Starship設定ファイル(~/.config/starship.toml):
# ~/.config/starship.toml
# プロンプトの先頭に空行を追加しない
add_newline = false
# プロンプト形式のカスタマイズ
format = """
$directory\
$git_branch\
$git_status\
$python\
$nodejs\
$golang\
$rust\
$kubernetes\
$docker_context\
$cmd_duration\
$line_break\
$character"""
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[✗](bold red)"
[directory]
truncation_length = 3
truncation_symbol = "…/"
style = "bold cyan"
[git_branch]
format = "[$symbol$branch(:$remote_branch)]($style) "
symbol = " "
style = "bold purple"
[git_status]
format = '([\[$all_status$ahead_behind\]]($style) )'
style = "bold red"
[python]
format = '[${symbol}${pyenv_prefix}(${version} )(\($virtualenv\) )]($style)'
symbol = " "
[nodejs]
format = "[$symbol($version )]($style)"
symbol = " "
[golang]
format = "[$symbol($version )]($style)"
symbol = " "
[rust]
format = "[$symbol($version )]($style)"
symbol = " "
[kubernetes]
disabled = false
format = '[$symbol$context( \($namespace\))]($style) '
symbol = "⎈ "
style = "bold blue"
[docker_context]
format = "[$symbol$context]($style) "
symbol = " "
[cmd_duration]
min_time = 2_000
format = "[$duration]($style) "
style = "bold yellow"
3. 【戦略1】シームレスなナビゲーション -- vim-tmux-navigator
3.1 問題:2つの世界の断絶
VimとTmuxはそれぞれ独立した分割システムを持っています。
┌─────────────────────────────────────────┐
│ Tmuxの世界 │
│ ┌──────────────┬──────────────────────┐ │
│ │ │ │ │
│ │ Vimの世界 │ │ │
│ │ ┌────┬────┐ │ Tmux Pane 2 │ │
│ │ │Vim │Vim │ │ (shell) │ │
│ │ │Split│Split│ │ │ │
│ │ │ 1 │ 2 │ │ │ │
│ │ └────┴────┘ │ │ │
│ │ │ │ │
│ │ Tmux Pane 1 │ │ │
│ └──────────────┴──────────────────────┘ │
└─────────────────────────────────────────┘
上のレイアウトで、Vim Split 2からTmux Pane 2に移動するには:
- Vimを操作:
Ctrl-w l(右のVim splitに移動しようとする...しかし右にsplitがない) - Tmuxプレフィックスを使用:
Ctrl-b l(右のTmux paneに移動)
毎回「今自分はVimの中にいるのか、Tmuxの中にいるのか?」を判断する必要があります。この認知的負荷が思考の流れを断ち切るのです。
3.2 解決策:vim-tmux-navigator
vim-tmux-navigatorはChris Toomeyが作成したプラグインで、Vim splitとTmux paneの境界を完全に透明にします。Ctrl-h/j/k/lという一貫したショートカットで、Vimの中でもTmuxの中でも、どの方向にも移動できます。
Vim/Neovim設定(vim-plug)
" ~/.vimrc or ~/.config/nvim/init.vim
call plug#begin('~/.vim/plugged')
Plug 'christoomey/vim-tmux-navigator'
call plug#end()
" ズーム中はナビゲーションを無効化(オプション)
let g:tmux_navigator_disable_when_zoomed = 1
" ナビゲーション中もズームを維持(オプション)
" let g:tmux_navigator_preserve_zoom = 1
Neovim設定(lazy.nvim)
-- ~/.config/nvim/lua/plugins/tmux-navigator.lua
return {
"christoomey/vim-tmux-navigator",
cmd = {
"TmuxNavigateLeft",
"TmuxNavigateDown",
"TmuxNavigateUp",
"TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<C-h>", "<cmd>TmuxNavigateLeft<cr>", desc = "Navigate Left" },
{ "<C-j>", "<cmd>TmuxNavigateDown<cr>", desc = "Navigate Down" },
{ "<C-k>", "<cmd>TmuxNavigateUp<cr>", desc = "Navigate Up" },
{ "<C-l>", "<cmd>TmuxNavigateRight<cr>", desc = "Navigate Right" },
},
}
Tmux設定(.tmux.conf)
# ~/.tmux.conf — vim-tmux-navigator連携
# TPM使用時
set -g @plugin 'christoomey/vim-tmux-navigator'
# または手動設定(TPM未使用時)
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?|fzf)(diff)?$'"
bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' 'select-pane -L'
bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' 'select-pane -D'
bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' 'select-pane -U'
bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' 'select-pane -R'
tmux_version='$(tmux -V | sed -En "s/^tmux ([0-9]+(.[0-9]+)?).*/\1/p")'
if-shell -b '[ "$(echo "$tmux_version >= 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
if-shell -b '[ "$(echo "$tmux_version < 3.0" | bc)" = 1 ]' \
"bind-key -n 'C-\\' if-shell \"$is_vim\" 'send-keys C-\\\\' 'select-pane -l'"
bind-key -T copy-mode-vi 'C-h' select-pane -L
bind-key -T copy-mode-vi 'C-j' select-pane -D
bind-key -T copy-mode-vi 'C-k' select-pane -U
bind-key -T copy-mode-vi 'C-l' select-pane -R
3.3 動作原理
vim-tmux-navigatorの動作原理は以下の通りです。
Ctrl-hを押す- Tmuxが現在のペインのプロセスを確認する(
is_vim変数) - Vimが動作中の場合:キーストロークがVimに転送され、Vimが左のsplitに移動しようとする
- Vim内に左のsplitがこれ以上ない場合、VimプラグインがTmuxコマンドを実行して左のTmux paneに移動する
- Vimでない場合:Tmuxが直接左のpaneに移動する
結果として、ユーザーは**「左に行きたいからCtrl-h」**とだけ考えればよくなります。Vim splitなのかTmux paneなのかを気にする必要はありません。
3.4 Ctrl-lの画面クリアを復元する
Ctrl-lは伝統的にターミナル画面をクリアするショートカットです。vim-tmux-navigatorがナビゲーションに使用するため、代替手段が必要です。
# ~/.tmux.conf — 画面クリアの復元
# prefix + Ctrl-l で画面クリア
bind C-l send-keys 'C-l'
これでprefix + Ctrl-lで画面をクリアできます。キーストロークが数回増えますが、ナビゲーションの一貫性による利点の方がはるかに大きいです。
3.5 フロー状態を維持するナビゲーション
vim-tmux-navigatorを適用した後のワークフローを可視化すると、以下のようになります。
思考の流れ(中断なし)
─────────────────────────────────────────────────────────
「この関数のテスト結果を確認しよう」
│
▼
Ctrl-j (下のVimuxペインに移動 — Vim/Tmuxの境界は透明)
│
▼
「テスト通過。ログを確認しよう」
│
▼
Ctrl-l (右のログペインに移動 — 境界も透明)
│
▼
「修正が必要。コードに戻ろう」
│
▼
Ctrl-h (左のVimに戻る)
│
▼
コード編集を続行...
— このプロセス全体を通じて、マウスに一度も触れていない —
4. 【戦略2】直感的なパネル分割 -- 視覚メタファーマッピング
4.1 問題:Tmuxのデフォルトキーバインドが直感的でない
Tmuxのデフォルトのペイン分割キーバインドは以下の通りです。
| 操作 | デフォルトキーバインド | 実際の意味 |
|---|---|---|
| 水平分割(上下) | prefix + " | 引用符?なぜ? |
| 垂直分割(左右) | prefix + % | パーセント記号?なぜ? |
これらのキーバインドには視覚的メタファーが一切ありません。"で水平線を連想できますか?%で垂直線を思い浮かべますか?全くできません。毎回「垂直分割は%だったか"だったか...」と記憶を探る必要があります。この認知的負荷は些細に見えますが、1日に何十回もペインを分割するとなると積み重なります。
4.2 解決策:視覚メタファーマッピング
# ~/.tmux.conf — 直感的なパネル分割
# | は垂直線に見える → 垂直分割(左右)
bind | split-window -h -c "#{pane_current_path}"
# - は水平線に見える → 水平分割(上下)
bind - split-window -v -c "#{pane_current_path}"
# デフォルトのキーバインドを削除(混乱を防止)
unbind '"'
unbind %
ここでのポイントは-c "#{pane_current_path}"オプションです。これがないと、新しいペインはホームディレクトリで開きます。このオプションを追加することで、分割時に現在の作業ディレクトリを保持します — 実際の運用では非常に重要な設定です。
4.3 視覚メタファーの効果
prefix + | prefix + -
分割前: 分割前:
┌──────────────┐ ┌──────────────┐
│ │ │ │
│ │ │ │
│ │ │ │
└──────────────┘ └──────────────┘
分割後: 分割後:
┌──────┬───────┐ ┌──────────────┐
│ │ │ │ │
│ │ │ ├──────────────┤
│ │ │ │ │
└──────┴───────┘ └──────────────┘
| = 垂直線 = 垂直分割 - = 水平線 = 水平分割
もう暗記する必要はありません。見た目通りに動作するのです。
4.4 実践的な開発レイアウトパターン
以下はよく使われる開発レイアウトパターンです。
パターン1:コード + テスト(TDD)
┌─────────────────────────┐
│ │
│ Vim(コード編集) │
│ │
│ │
├─────────────────────────┤
│ テストランナー(Vimux) │
└─────────────────────────┘
セットアップ:prefix + - を1回
パターン2:コード + ターミナル + ログ(フルスタック)
┌──────────────────┬──────────────┐
│ │ │
│ Vim(コード) │ サーバーログ │
│ │ │
│ │ │
├──────────────────┤ │
│ │ │
│ ターミナル(git, │ │
│ ビルド等) │ │
└──────────────────┴──────────────┘
セットアップ:prefix + | → 左側で prefix + -
パターン3:マイクロサービス監視(4分割)
┌──────────────────┬──────────────┐
│ │ │
│ サービスAログ │ サービスBログ│
│ │ │
├──────────────────┼──────────────┤
│ │ │
│ サービスCログ │ Metrics/htop│
│ │ │
└──────────────────┴──────────────┘
セットアップ:prefix + | → 各ペインで prefix + -
4.5 ペインリサイズショートカット
分割後のリサイズも直感的にしましょう。
# ~/.tmux.conf — ペインリサイズ
# Vim風の方向キーでリサイズ
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# -r フラグ:リピート可能(prefixを1回押した後、タイムアウト内でキーを繰り返し入力可能)
-rフラグがポイントです。prefix + Hを押した後、500ms以内に再度Hを押すと、プレフィックスなしで繰り返されます。高速なリサイズに非常に便利です。
5. 【戦略3】Vimux -- 超高速フィードバックループ
5.1 問題:コード-実行-確認ループの非効率性
従来の開発ワークフローは以下のようになります。
コード編集(Vim)
│
▼
Vimを終了またはCtrl-Z(サスペンド)
│
▼
ターミナルでコマンドを入力(pytest, go test, npm test...)
│
▼
結果を確認
│
▼
Vimに戻る(fgまたはvimを再起動)
│
▼
「どこを編集していたんだっけ...」
このループでは、コード編集と実行の間の遷移コストが大きいです。特にTDD(テスト駆動開発)では、このループが数秒ごとに繰り返されるため、累積的な遷移コストが致命的になります。
5.2 解決策:Vimux -- Vim内からシェルコマンドを実行
VimuxはVimから直接Tmuxペインにコマンドを送信するプラグインです。Vimを離れることなく、コードを見ながらテストを実行し、結果を確認できます。
インストール(vim-plug)
" ~/.vimrc
Plug 'preservim/vimux'
インストール(lazy.nvim)
-- ~/.config/nvim/lua/plugins/vimux.lua
return {
"preservim/vimux",
keys = {
{ "<Leader>vp", "<cmd>VimuxPromptCommand<cr>", desc = "Vimux Prompt" },
{ "<Leader>vl", "<cmd>VimuxRunLastCommand<cr>", desc = "Vimux Run Last" },
{ "<Leader>vi", "<cmd>VimuxInspectRunner<cr>", desc = "Vimux Inspect" },
{ "<Leader>vz", "<cmd>VimuxZoomRunner<cr>", desc = "Vimux Zoom" },
{ "<Leader>vc", "<cmd>VimuxCloseRunner<cr>", desc = "Vimux Close" },
},
config = function()
-- Vimuxペインの高さ(%)
vim.g.VimuxHeight = "30"
-- ペインの方向(水平・下部)
vim.g.VimuxOrientation = "v"
-- ランナータイプ
vim.g.VimuxRunnerType = "pane"
end,
}
5.3 コアコマンド
| コマンド | デフォルトマッピング | 説明 |
|---|---|---|
VimuxPromptCommand | <Leader>vp | コマンド入力プロンプト |
VimuxRunLastCommand | <Leader>vl | 最後のコマンドを再実行 |
VimuxRunCommand("...") | カスタム | 特定のコマンドを直接実行 |
VimuxInspectRunner | <Leader>vi | ランナーペインに移動(スクロール可能) |
VimuxZoomRunner | <Leader>vz | ランナーペインのフルスクリーン切り替え |
VimuxCloseRunner | <Leader>vc | ランナーペインを閉じる |
5.4 言語別TDDワークフロー設定
Python (pytest)
-- ~/.config/nvim/lua/plugins/vimux.lua に追加
-- Python:現在のファイルでテストを実行
vim.keymap.set("n", "<Leader>tt", function()
local file = vim.fn.expand("%")
vim.fn.VimuxRunCommand("pytest -v " .. file)
end, { desc = "Run pytest on current file" })
-- Python:カーソル位置のテスト関数のみ実行
vim.keymap.set("n", "<Leader>ts", function()
local file = vim.fn.expand("%")
local line = vim.fn.line(".")
-- pytest-pickedまたは行ベースの選択
vim.fn.VimuxRunCommand("pytest -v " .. file .. " --no-header -rN")
end, { desc = "Run pytest on current test" })
-- Python:全テストスイート
vim.keymap.set("n", "<Leader>ta", function()
vim.fn.VimuxRunCommand("pytest -v --tb=short")
end, { desc = "Run all tests" })
Go
-- Go:現在のパッケージをテスト
vim.keymap.set("n", "<Leader>tt", function()
vim.fn.VimuxRunCommand("go test -v ./...")
end, { desc = "Run Go tests" })
-- Go:現在のファイルのパッケージのみテスト
vim.keymap.set("n", "<Leader>tf", function()
local dir = vim.fn.expand("%:h")
vim.fn.VimuxRunCommand("go test -v ./" .. dir .. "/...")
end, { desc = "Run Go tests in current package" })
-- Go:ベンチマーク
vim.keymap.set("n", "<Leader>tb", function()
vim.fn.VimuxRunCommand("go test -bench=. -benchmem ./...")
end, { desc = "Run Go benchmarks" })
Node.js (Jest)
-- Jest:現在のファイルをテスト
vim.keymap.set("n", "<Leader>tt", function()
local file = vim.fn.expand("%")
vim.fn.VimuxRunCommand("npx jest " .. file .. " --verbose")
end, { desc = "Run Jest on current file" })
-- Jest:ウォッチモード
vim.keymap.set("n", "<Leader>tw", function()
local file = vim.fn.expand("%")
vim.fn.VimuxRunCommand("npx jest " .. file .. " --watch")
end, { desc = "Run Jest in watch mode" })
-- Jest:全テスト
vim.keymap.set("n", "<Leader>ta", function()
vim.fn.VimuxRunCommand("npx jest --verbose")
end, { desc = "Run all Jest tests" })
Rust
-- Rust:cargo test
vim.keymap.set("n", "<Leader>tt", function()
vim.fn.VimuxRunCommand("cargo test")
end, { desc = "Run cargo test" })
-- Rust:出力付きcargo test
vim.keymap.set("n", "<Leader>to", function()
vim.fn.VimuxRunCommand("cargo test -- --nocapture")
end, { desc = "Run cargo test with output" })
-- Rust:cargo clippy
vim.keymap.set("n", "<Leader>tc", function()
vim.fn.VimuxRunCommand("cargo clippy -- -W clippy::all")
end, { desc = "Run cargo clippy" })
5.5 Vimux TDDワークフローの可視化
「探して、読んで、実行する」を1つのコンテキストで
──────────────────────────────────────
┌─────────────────────────────────┐
│ Vim(コード編集) │
│ │
│ def add(a, b): │
│ return a + b ← 編集中 │
│ │
│ ~ │
│ ~ │
├─────────────────────────────────┤
│ Vimux Runner(テスト結果) │
│ │
│ $ pytest -v test_calc.py │
│ test_add PASSED ✓ │
│ test_subtract FAILED ✗ │
│ 1 failed, 1 passed │
└─────────────────────────────────┘
<Leader>tt → テスト実行(視線だけ移動、手はそのまま)
<Leader>vl → 最後のコマンドを再実行(編集後すぐに確認)
ポイントは、視線が一瞬下に移動するだけで、手はキーボードに留まり続けることです。コード編集とテスト実行の間の遷移コストは事実上ゼロになります。
6. 【戦略4】システムクリップボード同期
6.1 問題:ターミナルとOSの間の見えない壁
Vimでyyでテキストをコピーし、ブラウザでCmd-Vで貼り付けようとすると... 何も貼り付けられません。Vimのレジスタとシステムクリップボードは、デフォルトでは根本的に別の世界です。
Tmuxはさらに複雑さを加えます。Tmuxのコピーモードで選択したテキストはTmuxバッファに入りますが、これもシステムクリップボードとは無関係です。
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Vim │ │ Tmux │ │ OS │
│ Register │ ✗ │ Buffer │ ✗ │ Clipboard│
│ ("a, "b) │ │ (paste │ │ (Cmd-V) │
│ │←──→│ buffer) │←──→│ │
└──────────┘ └──────────┘ └──────────┘
切断状態 切断状態
目標:3つのシステムをすべて同期する
6.2 解決策:プラットフォーム別クリップボード設定
macOS
macOSはデフォルトでpbcopy / pbpasteユーティリティを提供するため、設定は比較的簡単です。
Tmux設定:
# ~/.tmux.conf — macOSクリップボード同期
# set-clipboardを有効化
set -s set-clipboard on
# コピーモードで選択後にシステムクリップボードにコピー
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
# マウスドラッグ後に自動コピー(マウス使用時)
bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"
# Enterキーでもクリップボードにコピー
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"
Neovim設定:
-- ~/.config/nvim/init.lua or lua/config/options.lua
-- システムクリップボードをunnamed plusレジスタとして使用
vim.opt.clipboard = "unnamedplus"
-- macOSでは、これだけで十分。
-- Neovimはpbcopy/pbpasteを自動検出する。
Linux (X11 -- xclip)
# xclipのインストール
sudo apt install -y xclip # Debian/Ubuntu
sudo pacman -S xclip # Arch
# ~/.tmux.conf
set -s set-clipboard on
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"
-- Neovim (Linux X11)
vim.opt.clipboard = "unnamedplus"
-- 明示的なクリップボードプロバイダ(オプション)
vim.g.clipboard = {
name = "xclip",
copy = {
["+"] = "xclip -selection clipboard",
["*"] = "xclip -selection primary",
},
paste = {
["+"] = "xclip -selection clipboard -o",
["*"] = "xclip -selection primary -o",
},
cache_enabled = 0,
}
Linux (Wayland -- wl-clipboard)
# wl-clipboardのインストール
sudo apt install -y wl-clipboard # Debian/Ubuntu
sudo pacman -S wl-clipboard # Arch
# ~/.tmux.conf
set -s set-clipboard on
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "wl-copy"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "wl-copy"
-- Neovim (Wayland)
vim.opt.clipboard = "unnamedplus"
vim.g.clipboard = {
name = "wl-clipboard",
copy = {
["+"] = "wl-copy",
["*"] = "wl-copy --primary",
},
paste = {
["+"] = "wl-paste --no-newline",
["*"] = "wl-paste --no-newline --primary",
},
cache_enabled = 0,
}
6.3 SSHリモート環境でのクリップボード同期
SSH経由でリモートサーバーに接続している場合、クリップボードの同期はさらに困難になります。OSC 52エスケープシーケンスを使用すると、リモートサーバーのTmuxからローカルのシステムクリップボードにコピーできます。
# ~/.tmux.conf(リモートサーバー)
# OSC 52によるクリップボード同期
set -s set-clipboard on
set -g allow-passthrough on
# ターミナルエミュレータがOSC 52をサポートしている必要あり
# Ghostty, Alacritty, WezTerm, iTerm2などがサポート
-- Neovim(リモートサーバー)— OSC 52サポート
-- Neovim 0.10+から組み込みサポート
vim.opt.clipboard = "unnamedplus"
-- OSC 52が自動検出されない場合の明示的な設定
vim.g.clipboard = {
name = "OSC 52",
copy = {
["+"] = require("vim.ui.clipboard.osc52").copy("+"),
["*"] = require("vim.ui.clipboard.osc52").copy("*"),
},
paste = {
["+"] = require("vim.ui.clipboard.osc52").paste("+"),
["*"] = require("vim.ui.clipboard.osc52").paste("*"),
},
}
6.4 統合後のワークフロー
クリップボード同期が完了すると、以下の自然なワークフローが可能になります。
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Vim │ │ Tmux │ │ OS │
│ Register │ ✓ │ Buffer │ ✓ │ Clipboard│
│ yy/p │◄──►│ copy-mode│◄──►│ Cmd-V │
└──────────┘ └──────────┘ └──────────┘
同期済み 同期済み
Vimでyy → ブラウザでCmd-V ✓
ブラウザでCmd-C → Vimでp ✓
Tmux copy-mode → Slackにペースト ✓
ツール間の壁が完全になくなります。 VimからコードスニペットをコピーしてSlackで共有する、ブラウザのエラーメッセージをコピーしてVimに貼り付ける — すべてがマウスなしで自然に行えます。
7. 【戦略5】Dotfilesと開発者アイデンティティ
7.1 設定ファイル管理 = 専門性の証明
Dotfiles(ドットで始まる設定ファイル — .vimrc、.tmux.conf、.zshrc、.gitconfigなど)は単なる設定ファイルではありません。長年にわたるワークフロー最適化の結晶です。
よく整備されたDotfilesリポジトリは以下を伝えます:
- この開発者がどのツールを使っているか
- どのようなワークフローを好むか
- 生産性にどれほど真剣に投資しているか
- 新しいマシンをどれほど速くセットアップできるか
7.2 Dotfiles管理ツールの比較
方法1:Git Bareリポジトリ(ミニマリスト)
# 初期セットアップ
git init --bare $HOME/.dotfiles
alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
dotfiles config --local status.showUntrackedFiles no
# .bashrcまたは.zshrcにエイリアスを追加
echo "alias dotfiles='git --git-dir=\$HOME/.dotfiles/ --work-tree=\$HOME'" >> ~/.zshrc
# ファイルを追加
dotfiles add ~/.tmux.conf
dotfiles add ~/.config/nvim/init.lua
dotfiles commit -m "Add tmux and neovim config"
dotfiles remote add origin git@github.com:username/dotfiles.git
dotfiles push -u origin main
# 新しいマシンで復元
git clone --bare git@github.com:username/dotfiles.git $HOME/.dotfiles
alias dotfiles='git --git-dir=$HOME/.dotfiles/ --work-tree=$HOME'
dotfiles checkout
メリット:外部依存なし、Gitのみで完結 デメリット:コンフリクト管理が煩雑、マシン固有のブランチ管理が困難
方法2:GNU Stow(シンボリックリンク)
# インストール
sudo apt install stow # Debian/Ubuntu
brew install stow # macOS
# ディレクトリ構造
~/dotfiles/
├── tmux/
│ └── .tmux.conf
├── nvim/
│ └── .config/
│ └── nvim/
│ └── init.lua
├── zsh/
│ └── .zshrc
└── starship/
└── .config/
└── starship.toml
# シンボリックリンクを作成
cd ~/dotfiles
stow tmux # ~/.tmux.conf → ~/dotfiles/tmux/.tmux.conf
stow nvim # ~/.config/nvim/init.lua → ~/dotfiles/nvim/.config/nvim/init.lua
stow zsh # ~/.zshrc → ~/dotfiles/zsh/.zshrc
stow starship # ~/.config/starship.toml → ~/dotfiles/starship/.config/starship.toml
# シンボリックリンクを削除
stow -D tmux
メリット:シンプルで直感的、パッケージ単位の管理 デメリット:テンプレート/シークレット管理機能なし
方法3:chezmoi(モダンエンタープライズ)
chezmoiは最も機能豊富なDotfiles管理ツールです。テンプレート、シークレット管理、マシン固有の分岐、暗号化をサポートします。
# インストール
brew install chezmoi # macOS
sudo apt install chezmoi # Debian/Ubuntu(snapも利用可能)
sh -c "$(curl -fsLS get.chezmoi.io)" # ユニバーサル
# 初期化
chezmoi init
# ファイルを追加
chezmoi add ~/.tmux.conf
chezmoi add ~/.config/nvim/init.lua
chezmoi add ~/.config/starship.toml
# 編集
chezmoi edit ~/.tmux.conf
# 変更をプレビュー
chezmoi diff
# 適用
chezmoi apply
# Gitリポジトリにプッシュ
chezmoi cd # chezmoiのソースディレクトリに移動
git add . && git commit -m "Update dotfiles" && git push
# 新しいマシンでのワンライン復元
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply username
chezmoiのテンプレート機能 -- マシン固有の設定分岐:
# ~/.local/share/chezmoi/dot_tmux.conf.tmpl
# 共通設定
set -g default-terminal "tmux-256color"
set -g mouse on
# クリップボード — OS固有の分岐
{{ if eq .chezmoi.os "darwin" -}}
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
{{ else if eq .chezmoi.os "linux" -}}
{{ if env "WAYLAND_DISPLAY" -}}
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "wl-copy"
{{ else -}}
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"
{{ end -}}
{{ end -}}
7.3 Dotfiles管理ツール比較表
| 項目 | Git Bare | GNU Stow | chezmoi |
|---|---|---|---|
| 依存関係 | Gitのみ | Git + Stow | Git + chezmoi |
| 学習曲線 | 低い | 低い | 中程度 |
| テンプレート | なし | なし | Goテンプレート |
| シークレット管理 | なし | なし | age, gpg, 1Password等 |
| マシン分岐 | 手動Gitブランチ | 手動 | 自動(OS、ホスト名等) |
| ワンライン復元 | 可能(スクリプト) | 可能 | chezmoi init --apply |
| 推奨対象 | ミニマリスト | 中規模 | マルチマシン管理 |
7.4 なぜVim + Tmuxが今でもゴールドスタンダードなのか
Zellijのような最新の代替手段が登場していますが、Vim + Tmuxの組み合わせがゴールドスタンダードであり続ける理由があります。
Zellij -- 魅力的だが、まだ十分ではない
Zellijは、Rustで書かれた最新のターミナルマルチプレクサで、モードベースのナビゲーションとリアルタイムキーバインドツールバーにより初心者にも使いやすいです。しかし:
- 未成熟なエコシステム:Tmuxの豊富なプラグインエコシステム(TPM、vim-tmux-navigatorなど)と比較して限定的
- Vim連携:vim-tmux-navigatorレベルのシームレスなナビゲーションはまだ発展途上
- リモートサーバー:Tmuxはほとんどのサーバーにプリインストール、Zellijはまだ未対応
- スクリプティング:Tmuxの成熟したコマンドシステムと比較して限定的
- メモリ:同等の条件下で約22MB(Tmuxより多い)
とはいえ、Zellijを軽視すべきではありません。初心者やローカル開発環境のみを使用する場合、Zellijの直感的なUIは確かに魅力的です。
7.5 ターミナルエミュレータの比較
| 項目 | Ghostty | Alacritty | WezTerm | Kitty | iTerm2 |
|---|---|---|---|---|---|
| 言語 | Zig | Rust | Rust | C/Python | Obj-C |
| GPUアクセラレーション | Metal/OpenGL | OpenGL | OpenGL | OpenGL | Metal |
| ネイティブUI | あり | なし | なし | なし | あり(macOS) |
| 設定 | テキストファイル | YAMLからTOML | Lua | confファイル | GUI |
| リガチャ | あり | なし | あり | あり | あり |
| 画像レンダリング | Kittyプロトコル | なし | あり | あり | あり |
| タブ/分割 | あり(ネイティブ) | なし | あり | あり | あり |
| macOS | あり | あり | あり | あり | あり |
| Linux | あり | あり | あり | あり | なし |
| Windows | 予定 | あり | あり | なし | なし |
| Nerd Fontデフォルト | あり | なし | なし | なし | なし |
| 特徴 | ゼロコンフィグ起動 | 超ミニマル | Luaスクリプティング | 組み込みマルチプレクサ | macOS最適化 |
Tmuxとの併用時の推奨:Tmuxがマルチプレキシングを担うため、ターミナルエミュレータ独自のタブ/分割機能は不要です。GPUアクセラレーション、フォントレンダリング、安定性に注目しましょう。Ghosttyはゼロコンフィグで起動しながら、Nerd Fontのデフォルトサポート、Metalアクセラレーション、Kittyプロトコル — 必要な機能をすべて備えており、Tmuxとの相性が抜群です。
8. 完全な設定ファイル(コピー&ペースト対応)
8.1 完全な.tmux.conf
# ============================================================
# .tmux.conf — 最大の生産性のための完全な設定
# ============================================================
# ─── 基本設定 ─────────────────────────────────────────
# 256色とTrue Colorサポート
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
set -ag terminal-overrides ",*256col*:Tc"
# 履歴サイズ
set -g history-limit 50000
# エスケープシーケンスの遅延を最小化(Vimにとって重要)
set -sg escape-time 0
# リピートキーのタイムアウト
set -g repeat-time 500
# フォーカスイベントを有効化(Vimのautoread等に必要)
set -g focus-events on
# インデックスを1から開始(0はキーボードの端で遠い)
set -g base-index 1
setw -g pane-base-index 1
# ウィンドウ番号の自動振り直し
set -g renumber-windows on
# マウスサポート
set -g mouse on
# Viキーモード
setw -g mode-keys vi
# ─── プレフィックスキーの変更 ──────────────────────────────────────
# Ctrl-aはCtrl-bより押しやすい
unbind C-b
set -g prefix C-a
bind C-a send-prefix
# ─── 直感的なパネル分割【戦略2】─────────────────
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"
unbind '"'
unbind %
# 新しいウィンドウも現在のパスを保持
bind c new-window -c "#{pane_current_path}"
# ─── ペインリサイズ ──────────────────────────────────────────
bind -r H resize-pane -L 5
bind -r J resize-pane -D 5
bind -r K resize-pane -U 5
bind -r L resize-pane -R 5
# ─── vim-tmux-navigator【戦略1】───────────────────────
# TPM経由でインストールする場合は1行で十分
set -g @plugin 'christoomey/vim-tmux-navigator'
# Ctrl-lの画面クリアを復元
bind C-l send-keys 'C-l'
# ─── コピーモードとクリップボード【戦略4】─────────────────
# Vi風コピーモード
bind-key -T copy-mode-vi v send-keys -X begin-selection
bind-key -T copy-mode-vi C-v send-keys -X rectangle-toggle
bind-key -T copy-mode-vi y send-keys -X copy-selection-and-cancel
# システムクリップボード同期
set -s set-clipboard on
# macOS
if-shell "uname | grep -q Darwin" {
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "pbcopy"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "pbcopy"
bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "pbcopy"
}
# Linux (X11)
if-shell "[ -n \"$DISPLAY\" ] && command -v xclip > /dev/null" {
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -selection clipboard"
}
# Linux (Wayland)
if-shell "[ -n \"$WAYLAND_DISPLAY\" ] && command -v wl-copy > /dev/null" {
bind-key -T copy-mode-vi y send-keys -X copy-pipe-and-cancel "wl-copy"
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "wl-copy"
}
# ─── ステータスバーのカスタマイズ ──────────────────────────────
set -g status-position bottom
set -g status-style "bg=#1e1e2e,fg=#cdd6f4"
set -g status-left-length 40
set -g status-right-length 80
set -g status-left "#[fg=#1e1e2e,bg=#89b4fa,bold] #S #[fg=#89b4fa,bg=#1e1e2e] "
set -g status-right "#[fg=#a6adc8] %Y-%m-%d %H:%M #[fg=#1e1e2e,bg=#a6e3a1,bold] #H "
# ウィンドウステータスバー
setw -g window-status-format "#[fg=#6c7086] #I:#W "
setw -g window-status-current-format "#[fg=#1e1e2e,bg=#cba6f7,bold] #I:#W "
# ペイン境界線
set -g pane-border-style "fg=#313244"
set -g pane-active-border-style "fg=#89b4fa"
# ─── ユーティリティ ────────────────────────────────────────────
# 設定のリロード
bind r source-file ~/.tmux.conf \; display-message "Config reloaded!"
# セッション切り替え
bind s choose-tree -Zs
# 同期入力の切り替え(すべてのペインに同じ入力)
bind S setw synchronize-panes \; display-message "Synchronize #{?synchronize-panes,ON,OFF}"
# ─── TPM(Tmux Plugin Manager)───────────────────────
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-resurrect'
set -g @plugin 'tmux-plugins/tmux-continuum'
# tmux-resurrect:Neovimセッション復元
set -g @resurrect-strategy-nvim 'session'
# tmux-continuum:自動保存
set -g @continuum-restore 'on'
set -g @continuum-save-interval '15'
# TPMの初期化(最後に配置する必要あり)
run '~/.tmux/plugins/tpm/tpm'
8.2 完全なNeovim init.lua(Vim + Tmux連携部分)
以下はkickstart.nvimをベースに、Vim + Tmux連携のコア設定を抜粋したものです。
-- ============================================================
-- Neovim init.lua — Vim + Tmux連携コア設定
-- kickstart.nvimベース
-- ============================================================
-- ─── 基本オプション ──────────────────────────────────────
vim.g.mapleader = " " -- Leader = スペース
vim.g.maplocalleader = " "
vim.opt.number = true -- 行番号
vim.opt.relativenumber = true -- 相対行番号
vim.opt.signcolumn = "yes" -- サイン列を常に表示
vim.opt.cursorline = true -- 現在行をハイライト
vim.opt.termguicolors = true -- True Color
vim.opt.scrolloff = 8 -- スクロールマージン
vim.opt.sidescrolloff = 8
vim.opt.wrap = false -- 行の折り返しを無効化
-- 検索
vim.opt.ignorecase = true
vim.opt.smartcase = true
vim.opt.hlsearch = true
vim.opt.incsearch = true
-- インデント
vim.opt.expandtab = true
vim.opt.shiftwidth = 2
vim.opt.tabstop = 2
vim.opt.smartindent = true
-- システムクリップボード同期【戦略4】
vim.opt.clipboard = "unnamedplus"
-- ファイル変更の自動検出(Tmuxのfocus-eventsと連携)
vim.opt.autoread = true
vim.api.nvim_create_autocmd({ "FocusGained", "BufEnter" }, {
command = "checktime",
})
-- ─── lazy.nvim ブートストラップ ────────────────────────────────
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
"git", "clone", "--filter=blob:none",
"https://github.com/folke/lazy.nvim.git",
"--branch=stable", lazypath,
})
end
vim.opt.rtp:prepend(lazypath)
-- ─── プラグイン ──────────────────────────────────────────
require("lazy").setup({
-- vim-tmux-navigator【戦略1】
{
"christoomey/vim-tmux-navigator",
cmd = {
"TmuxNavigateLeft",
"TmuxNavigateDown",
"TmuxNavigateUp",
"TmuxNavigateRight",
"TmuxNavigatePrevious",
},
keys = {
{ "<C-h>", "<cmd>TmuxNavigateLeft<cr>", desc = "Navigate Left" },
{ "<C-j>", "<cmd>TmuxNavigateDown<cr>", desc = "Navigate Down" },
{ "<C-k>", "<cmd>TmuxNavigateUp<cr>", desc = "Navigate Up" },
{ "<C-l>", "<cmd>TmuxNavigateRight<cr>", desc = "Navigate Right" },
},
},
-- Vimux【戦略3】
{
"preservim/vimux",
keys = {
{ "<Leader>vp", "<cmd>VimuxPromptCommand<cr>", desc = "Vimux Prompt" },
{ "<Leader>vl", "<cmd>VimuxRunLastCommand<cr>", desc = "Vimux Run Last" },
{ "<Leader>vi", "<cmd>VimuxInspectRunner<cr>", desc = "Vimux Inspect" },
{ "<Leader>vz", "<cmd>VimuxZoomRunner<cr>", desc = "Vimux Zoom" },
{ "<Leader>vc", "<cmd>VimuxCloseRunner<cr>", desc = "Vimux Close" },
},
config = function()
vim.g.VimuxHeight = "30"
vim.g.VimuxOrientation = "v"
vim.g.VimuxRunnerType = "pane"
-- 言語別テスト実行マッピング
-- Python
vim.keymap.set("n", "<Leader>tp", function()
vim.fn.VimuxRunCommand("pytest -v " .. vim.fn.expand("%"))
end, { desc = "Run pytest" })
-- Go
vim.keymap.set("n", "<Leader>tg", function()
vim.fn.VimuxRunCommand("go test -v ./...")
end, { desc = "Run go test" })
-- Node.js
vim.keymap.set("n", "<Leader>tj", function()
vim.fn.VimuxRunCommand("npx jest " .. vim.fn.expand("%") .. " --verbose")
end, { desc = "Run jest" })
-- Rust
vim.keymap.set("n", "<Leader>tr", function()
vim.fn.VimuxRunCommand("cargo test")
end, { desc = "Run cargo test" })
-- ユニバーサル:最後のテストを再実行
vim.keymap.set("n", "<Leader>tl", function()
vim.fn.VimuxRunLastCommand()
end, { desc = "Run last test" })
end,
},
-- Telescope(ファジーファインダー)
{
"nvim-telescope/telescope.nvim",
branch = "0.1.x",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<Leader>ff", "<cmd>Telescope find_files<cr>", desc = "Find Files" },
{ "<Leader>fg", "<cmd>Telescope live_grep<cr>", desc = "Live Grep" },
{ "<Leader>fb", "<cmd>Telescope buffers<cr>", desc = "Buffers" },
{ "<Leader>fh", "<cmd>Telescope help_tags<cr>", desc = "Help Tags" },
},
},
-- Treesitter(シンタックスハイライト)
{
"nvim-treesitter/nvim-treesitter",
build = ":TSUpdate",
config = function()
require("nvim-treesitter.configs").setup({
ensure_installed = {
"lua", "vim", "vimdoc", "python", "go",
"javascript", "typescript", "rust", "bash",
"json", "yaml", "toml", "markdown",
},
highlight = { enable = true },
indent = { enable = true },
})
end,
},
-- テーマ
{
"catppuccin/nvim",
name = "catppuccin",
priority = 1000,
config = function()
require("catppuccin").setup({
flavour = "mocha",
transparent_background = false,
integrations = {
telescope = true,
treesitter = true,
which_key = true,
},
})
vim.cmd.colorscheme("catppuccin")
end,
},
-- which-key(キーバインドのディスカバリ)
{
"folke/which-key.nvim",
event = "VeryLazy",
config = function()
require("which-key").setup()
end,
},
})
-- ─── 追加キーマッピング ────────────────────────────
-- ESCで検索ハイライトをクリア
vim.keymap.set("n", "<Esc>", "<cmd>nohlsearch<cr>")
-- 分割ウィンドウのナビゲーション(vim-tmux-navigatorと重複、参考用)
-- vim.keymap.set("n", "<C-h>", "<C-w>h")
-- vim.keymap.set("n", "<C-j>", "<C-w>j")
-- vim.keymap.set("n", "<C-k>", "<C-w>k")
-- vim.keymap.set("n", "<C-l>", "<C-w>l")
-- ビジュアルモードで選択ブロックを移動
vim.keymap.set("v", "J", ":m '>+1<cr>gv=gv")
vim.keymap.set("v", "K", ":m '<-2<cr>gv=gv")
-- 画面を中央に保つ
vim.keymap.set("n", "<C-d>", "<C-d>zz")
vim.keymap.set("n", "<C-u>", "<C-u>zz")
vim.keymap.set("n", "n", "nzzzv")
vim.keymap.set("n", "N", "Nzzzv")
9. 生産性の測定:ワークフロー比較
9.1 タスク別の時間比較
以下は、日常の開発タスクについて、GUI中心のワークフローとVim + Tmuxワークフローの体感時間を比較したものです。(経験豊富なユーザーを基準に、マイクロ秒からの秒単位の累積効果を測定)
| タスク | GUI中心 | Vim + Tmux | 削減率 |
|---|---|---|---|
| ファイルを開く | 3-5秒(フォルダ参照、クリック) | 0.5-1秒(<Leader>ff) | 約80% |
| コードからターミナルへの切り替え | 2-3秒(Alt-Tab、マウス) | 0.2秒(Ctrl-j) | 約90% |
| テスト実行 | 3-5秒(ターミナル切り替え、コマンド入力) | 0.3秒(<Leader>tt) | 約90% |
| テキストを別アプリにコピー | 2-4秒(マウスドラッグ、Ctrl-C) | 0.5秒(yy→Cmd-V) | 約80% |
| 環境の復元(再起動後) | 5-15分(アプリ再起動、再配置) | 10秒(tmux attach) | 約99% |
| ウィンドウレイアウトの構築 | 1-3分(マウスドラッグ、リサイズ) | 10秒(prefix + |、-) | 約90% |
9.2 日次の累積効果
8時間の開発日における各タスクの頻度を仮定した場合:
┌────────────────────────────────────────────────────┐
│ 推定日次コンテキストスイッチ累積コスト │
├────────────────────────────────────────────────────┤
│ │
│ ファイルオープン:50回/日 × 3秒節約 = 150秒(2.5分) │
│ ウィンドウ切替:200回/日 × 2秒節約 = 400秒(6.7分) │
│ テスト:30回/日 × 3秒節約 = 90秒(1.5分) │
│ コピー&ペースト:40回/日 × 2秒節約 = 80秒(1.3分) │
│ その他操作:100回/日 × 1秒節約 = 100秒(1.7分) │
│ │
│ ───────────────────────────────────────────── │
│ 日次節約:約14分(純粋な操作時間) │
│ + 認知的負荷軽減による集中力向上:測定不能 │
│ + フロー状態維持効果:測定不能 │
│ │
│ 年間(営業日250日):約58時間 │
│ = 7.25営業日 │
└────────────────────────────────────────────────────┘
14分という数字は純粋な操作時間のみを計上しています。実際にはより重要なのは認知的負荷の軽減とフロー状態の維持効果で、これらは定量化が難しいですが、主観的にはずっと大きく感じられます。マウスに手を伸ばさないということは、思考の流れが一度も途切れないということであり、それこそが生産性の真の核心なのです。
10. トラブルシューティングとFAQ
10.1 vim-tmux-navigatorが遅い
一部の環境では、vim-tmux-navigatorのis_vimチェックが遅延を引き起こすことがあります。その場合、プラグインなしで直接実装する方法があります。
# ~/.tmux.conf — 軽量な代替手段(プラグインなし)
is_vim="ps -o state= -o comm= -t '#{pane_tty}' \
| grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|l?n?vim?x?)(diff)?$'"
bind-key -n C-h if-shell "$is_vim" "send-keys C-h" "select-pane -L"
bind-key -n C-j if-shell "$is_vim" "send-keys C-j" "select-pane -D"
bind-key -n C-k if-shell "$is_vim" "send-keys C-k" "select-pane -U"
bind-key -n C-l if-shell "$is_vim" "send-keys C-l" "select-pane -R"
Neovim側の設定(Lua、プラグインなし):
-- Neovim側の軽量実装
local function navigate(direction)
local nr = vim.fn.winnr()
vim.cmd("wincmd " .. direction)
if nr == vim.fn.winnr() then
local tmux_dir = ({ h = "L", j = "D", k = "U", l = "R" })[direction]
vim.fn.system("tmux select-pane -" .. tmux_dir)
end
end
vim.keymap.set("n", "<C-h>", function() navigate("h") end)
vim.keymap.set("n", "<C-j>", function() navigate("j") end)
vim.keymap.set("n", "<C-k>", function() navigate("k") end)
vim.keymap.set("n", "<C-l>", function() navigate("l") end)
10.2 Tmuxで色が崩れる
# ~/.tmux.conf
set -g default-terminal "tmux-256color"
set -ag terminal-overrides ",xterm-256color:RGB"
# Ghostty使用時
set -ag terminal-overrides ",xterm-ghostty:RGB"
10.3 NeovimでESCの応答が遅い
原因はTmuxのescape-time設定です。
# ~/.tmux.conf
set -sg escape-time 0 # デフォルトは500ms — 0に設定する必要あり
10.4 SSH経由でクリップボードが動作しない
OSC 52のサポートを確認してください。
# ターミナルエミュレータのOSC 52サポートを確認(ローカル)
printf '\033]52;c;%s\a' $(echo -n "test" | base64)
# その後Cmd-Vで"test"がペーストできれば、OSC 52はサポートされている
# Tmuxの設定
set -s set-clipboard on
set -g allow-passthrough on
10.5 再起動後にTmuxセッションが消える
tmux-resurrectとtmux-continuumプラグインを使用してください。(セクション8.1の完全な.tmux.confに含まれています)
11. まとめ:最小抵抗の道
11.1 「1秒」の問い
開発環境を最適化する際に、自分に問いかけるべき1つの質問があります。
「この操作に1秒以上かかっていないか?」
もしかかっているなら、自動化またはショートカットの候補です。VimとTmuxの組み合わせは、この質問に対する体系的な回答システムです。
- ファイルを開く? --
<Leader>ff(1秒以内) - 隣のパネルに移動する? --
Ctrl-h/j/k/l(0.2秒) - テストを実行する? --
<Leader>tt(0.3秒) - テキストをコピーする? --
yy(0.1秒、システムクリップボード自動同期) - 昨日の作業環境を復元する? --
tmux attach(1秒)
11.2 最小抵抗の道
水は常に最小抵抗の道を流れます。開発者のワークフローも同じです。特定の操作の抵抗(摩擦)が高ければその操作を避け、抵抗が低ければ自然とその道を辿ります。
Vim + Tmuxは、コード編集、実行、検証、修正という開発の核心ループにおいて抵抗を極限まで低減します。マウスに手を伸ばす、Alt-Tabでターミナルウィンドウを探す、コマンドを再入力する — これらすべてのマイクロフリクションが消えたとき、開発者は思考の速度でコーディングできるようになるのです。
11.3 始めるためのロードマップ
一度にすべてを採用する必要はありません。段階的なアプローチを取りましょう。
第1週:Tmuxの基本 + 直感的なパネル分割(|、-)
│
▼
第2週:vim-tmux-navigatorの設定(Ctrl-h/j/k/l)
│
▼
第3週:Vimuxの設定 + よく使うテストコマンドのマッピング
│
▼
第4週:クリップボード同期 + DotfilesのGit管理開始
│
▼
2ヶ月目以降:自分だけのワークフローを磨き上げる
│
▼
∞:「マウスに触れない喜び」
1週間に1つの戦略を採用すれば、1ヶ月で完全なVim + Tmux統合環境が完成します。重要なのは、すべてを一度に変えようとしないことです。各戦略が自然に感じられるようになってから、次の戦略に進みましょう。
マウスに触れないことは、単なる技術的な選択ではありません。思考と行動のギャップを埋め、最終的に開発者としての表現力を最大化することなのです。
12. 参考文献
- vim-tmux-navigator (GitHub) -- Chris Toomeyのシームレスナビゲーションプラグイン
- Vimux (GitHub) -- VimからTmuxペインにコマンドを送信するプラグイン
- kickstart.nvim (GitHub) -- 初心者向けNeovim設定の出発点
- Ghostty -- GPUアクセラレーション対応のネイティブUIターミナルエミュレータ
- Zellij -- Rustベースの最新ターミナルマルチプレクサ
- chezmoi -- マルチマシンDotfiles管理ツール
- GNU Stow -- シンボリックリンクベースのDotfiles管理
- Starship -- クロスシェル対応のカスタマイズ可能なプロンプト
- Monaspace (GitHub) -- GitHub Nextの等幅フォントスーパーファミリー
- Tmux Plugin Manager (TPM) -- Tmuxプラグインマネージャ
- tmux-resurrect -- Tmuxセッションの保存/復元
- tmux-continuum -- Tmuxセッションの自動保存
- Neovim -- 超拡張可能なVimベースのテキストエディタ
- Tmux and Vim -- even better together (SmartBear) -- TmuxとVimの統合ガイド
- Terminal Multiplexers: tmux vs Zellij (dasroot.net) -- 2026年版Tmux vs Zellij比較
クイズ
Q1: 「マウスに触れない喜び:ターミナル生産性を最大化する5つの核心戦略」の主なトピックは何ですか?
vim-tmux-navigatorによるシームレスなナビゲーション、直感的なパネル分割、Vimuxによる超高速フィードバックループ、システムクリップボード同期、Dotfiles管理 — VimとTmuxでターミナル生産性を最大化する5つの核心戦略を、実践的な設定とともに徹底解説。
Q2: ゼロから始める:環境構築の主な手順は何ですか?
戦略に入る前に、完全に新しいマシンからVim + Tmux開発環境を構築する手順を説明します。 2.1 ターミナルエミュレータのインストール:Ghostty GhosttyはZigで書かれたGPUアクセラレーション対応のターミナルエミュレータで、macOSではMetal、LinuxではOpenGLを使用します。2025年の一般公開以来、コミュニティから急速に注目を集めています。
Q3: 戦略1シームレスなナビゲーション -- vim-tmux-navigatorの核心的な概念を説明してください。
3.1 問題:2つの世界の断絶 VimとTmuxはそれぞれ独立した分割システムを持っています。 上のレイアウトで、Vim Split 2からTmux Pane 2に移動するには: Vimを操作:Ctrl-w l(右のVim splitに移動しようとする...しかし右にsplitがない) Tmuxプレフィックスを使用:Ctrl-b l(右のTmux paneに移動) 毎回「今自分はVimの中にいるのか、Tmuxの中にいるのか?」を判断する必要があります。この認知的負荷が思考の流れを断ち切るのです。
Q4: 戦略2直感的なパネル分割 -- 視覚メタファーマッピングの主な特徴は何ですか?
4.1 問題:Tmuxのデフォルトキーバインドが直感的でない Tmuxのデフォルトのペイン分割キーバインドは以下の通りです。 これらのキーバインドには視覚的メタファーが一切ありません。"で水平線を連想できますか?%で垂直線を思い浮かべますか?全くできません。毎回「垂直分割は%だったか"だったか...」と記憶を探る必要があります。この認知的負荷は些細に見えますが、1日に何十回もペインを分割するとなると積み重なります。 4.2 解決策:視覚メタファーマッピング ここでのポイントは-c "#{pane_current_path}"オプションです。
Q5: 戦略3Vimux -- 超高速フィードバックループはどのように機能しますか?
5.1 問題:コード-実行-確認ループの非効率性 従来の開発ワークフローは以下のようになります。 このループでは、コード編集と実行の間の遷移コストが大きいです。特にTDD(テスト駆動開発)では、このループが数秒ごとに繰り返されるため、累積的な遷移コストが致命的になります。 5.2 解決策:Vimux -- Vim内からシェルコマンドを実行 VimuxはVimから直接Tmuxペインにコマンドを送信するプラグインです。Vimを離れることなく、コードを見ながらテストを実行し、結果を確認できます。