Skip to content
Published on

マウスに触れない喜び:ターミナル生産性を最大化する5つの核心戦略

Authors
  • Name
    Twitter

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-Cyy(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/lw/b/edd/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│ │                      │ │
│  │  │ 12  │ │                      │ │
│  │  └────┴────┘ │                      │ │
│  │              │                      │ │
│  │  Tmux Pane 1 │                      │ │
│  └──────────────┴──────────────────────┘ │
└─────────────────────────────────────────┘

上のレイアウトで、Vim Split 2からTmux Pane 2に移動するには:

  1. Vimを操作Ctrl-w l(右のVim splitに移動しようとする...しかし右にsplitがない)
  2. 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の動作原理は以下の通りです。

  1. Ctrl-hを押す
  2. Tmuxが現在のペインのプロセスを確認する(is_vim変数)
  3. Vimが動作中の場合:キーストロークがVimに転送され、Vimが左のsplitに移動しようとする
  4. Vim内に左のsplitがこれ以上ない場合、VimプラグインがTmuxコマンドを実行して左のTmux paneに移動する
  5. 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     │    │ OSRegister │ ✗  │ 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     │    │ OSRegister │ ✓  │ Buffer   │ ✓  │ Clipboard│
 │ yy/p     │◄──►│ copy-mode│◄──►│ Cmd-V └──────────┘    └──────────┘    └──────────┘
      同期済み            同期済み

 Vimでyy → ブラウザでCmd-V ブラウザでCmd-CVimで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 BareGNU Stowchezmoi
依存関係GitのみGit + StowGit + 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 ターミナルエミュレータの比較

項目GhosttyAlacrittyWezTermKittyiTerm2
言語ZigRustRustC/PythonObj-C
GPUアクセラレーションMetal/OpenGLOpenGLOpenGLOpenGLMetal
ネイティブUIありなしなしなしあり(macOS)
設定テキストファイルYAMLからTOMLLuaconfファイル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-resurrecttmux-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. 参考文献

クイズ

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を離れることなく、コードを見ながらテストを実行し、結果を確認できます。