vde-layoutの使い方――tmuxのレイアウトをコマンド一発で再現

筆者のtmuxのレイアウトは、どのウィンドウでもほぼ似たような感じです。
左上にエディタ、左下に開発サーバー、右上にClaude Code、右下にeditprompt。

自分のいつものtmuxレイアウト

分割・サイズ調整・コマンド実行を 1日に数回繰り返すのが面倒 でした。また、 対角ペインへの移動は別ペイン経由が必須 なのも面倒でした。

「この面倒を解消してくれるツールvde-layoutがあったな」とvim-jpのSlackで思い出しました。使ってみたら良かったので解説します。

## vde-layoutとは

vde-layoutはターミナルのレイアウトをYAMLファイルで宣言的に定義して、コマンドを叩くだけで サクッとレイアウトを適用 できるツールです。
tmuxのほか、weztermにも対応しているようです。

単に画面を分割したりサイズを調整するだけでなく、 ペインを開きつつ指定したコマンドを実行できます

## 導入方法

導入方法を載せておきますが、最新の手順はリポジトリのREADMEをご覧ください。

### 前提

  • Node.js:22以上
  • tmuxのレイアウトの場合: tmux2.0以上
  • weztermのレイアウトの場合:weztermのnightlyビルド

※この記事はvde-layout v1.1.1で確認して書きました。

### インストール

npmでパッケージとして公開されているので、npmでインストールします。

Terminal window
npm install -g vde-layout

筆者はbunを使ってインストールしました。

Terminal window
bun add -g vde-layout

## 設定ファイルの配置

全体の設定は~/.config/vde/layout/config.ymlに書きます。拡張子はymlじゃないと認識されません。

※プロジェクト毎の設定は ./.vde/layout/config.yml に置きます。

## レイアウトの書き方

レイアウトの一覧はpresetsに書き、レイアウト自体はlayoutに書きます。

presets:
test: # vde-layout test のように引数で指定する時のプリセット名
name: test # tmuxやweztermでの表示名
description: Editor/Server | Claude # 人間用の説明
layout:
# ...

### 先に分割無しの書き方

ペイン毎の設定を説明するために、「分割無しのレイアウト」を先に解説します。

「新しいウィンドウでログを開く」というレイアウトです。

presets:
logs:
name: logs
command: tail -f /var/log/system.log
windowMode: new-window # new-window | current-window

次のコマンドを実行するとレイアウトが作成されます。

Terminal window
vde-layout logs

layoutを指定せずcommandを書くと分割無しになります。

windowModeは次の2つを指定できます。

  • new-window:新しいウィンドウで開く
  • current-window:他のペインを閉じてから今のウィンドウで開く

設定ファイルには書かずに引数で--current-windowなどの指定もできます。

### 分割レイアウト

分割する場合はtyperatiopanesを指定します。

layout:
type: vertical
ratio: [7, 3]
panes:
# 上
- name: editor
command: nvim
focus: true # 起動後にこのペインへフォーカス
# 下
- name: terminal

nameはペインの名前、commandはコマンドです。
commandは未指定でも大丈夫です(単にペインを開くだけ)。

#### type

  • horizontal(左右に分割)
  • vertical(上下に分割)

#### ratio

サイズを書きます。数字なら割合、"12c"のように書いたらセルの数で幅や高さを指定できます。

### 分割をネストしたレイアウト

続いて、分割のネストしたレイアウトです。

panesをネストして書きます。

layout:
type: horizontal
ratio: [1, 1]
panes:
# 左側
- type: vertical
ratio: [1, "7c"]
panes:
# 左上
- name: "other"
# 左下
- name: "server"
# 右側
- type: vertical
ratio: [1, "7c"]
panes:
# 右上
- name: "claude"
command: claude
# 右下
- name: "editprompt"
command: >-
editprompt open --editor nvim --target-pane {{pane_id:claude}} --always-copy
ephemeral: true # 実行後にペインを閉じる
focus: true

{{pane_id:claude}}のように書くと、指定したペインのIDを埋め込めます。

その他にもenvで環境変数、cwdでディレクトリ指定などができます。詳しくはREADMEを見てください。

## 筆者の設定

ここからは筆者が実際に使っている設定の紹介です。

### 特定の種類のキーバインドにジャンプ

記事冒頭に書いたように、筆者はたまに 対角のペインに移動したくなります
これを次のように設定することで1キーバインドだけで移動できるようにしました。

  • vde-layout起動時にtmuxのペイン変数@roleにペインの種類を書いておく(claudeserverなど)
  • 「ペイン変数@roleが指定した種類のペインに移動」というキーバインドを設定

#### レイアウト設定

command;を使い、複数コマンド実行してます。

presets:
dev:
name: dev
description: Editor/Server | AI/editprompt
layout:
type: horizontal
ratio: [1, 1]
panes:
- type: vertical
ratio: [1, "12c"]
panes:
- name: "other"
command: >-
tmux set-option -p -t {{this_pane}} @role other;
git status -s | grep . || echo '変更なし'
- name: "server"
command: "tmux set-option -p -t {{this_pane}} @role server"
- type: vertical
ratio: [1, "10c"]
panes:
- name: "claude"
command: >-
tmux set-option -p -t {{this_pane}} @role claude;
claude
- name: "editprompt"
command: >-
tmux set-option -p -t {{this_pane}} @role editprompt;
node ~/ghq/github.com/eetann/editprompt/dist/index.js open --editor nvim --target-pane {{pane_id:claude}} --always-copy
ephemeral: true
focus: true

#### フォーカス用のスクリプト

続いて、キーバインドで実行する処理です。今のウィンドウのペインを取ってきて、@roleが指定したペインの種類ならフォーカスします。

#!/bin/bash
if [ -z "$TMUX" ]; then
echo "Error: This command must be run inside tmux."
exit 1
fi
if [ -z "$1" ]; then
echo "Usage: tmux-focus-pane role"
exit 1
fi
pane_id=$(tmux list-panes -F "#{pane_id} #{@role}" | awk -v t="$1" '$2 == t {print $1}')
if [ -n "$pane_id" ]; then
tmux select-pane -t "$pane_id"
else
# フォーカスできなかったことを伝えるため
exit 1
fi

これをtmux-focus-paneとして呼び出せるようにします。

#### キーバインドを設定

-nを付けることで、tmuxのprefix無しでさきほど書いたスクリプトtmux-focus-paneを実行します。

.tmux.conf
bind-key -N "otherペインにフォーカス" -n M-e run-shell "tmux-focus-pane other"
bind-key -N "serverペインにフォーカス" -n M-s run-shell "tmux-focus-pane server"
bind-key -N "claudeペインにフォーカス" -n M-c run-shell "tmux-focus-pane claude"
bind-key -N "editpromptペインにフォーカス" -n M-q run-shell '\
#{@editprompt-cmd} resume --target-pane #{pane_id} || \
tmux-focus-pane editprompt || \
tmux split-window -v -l 10 -c "#{pane_current_path}" \
"tmux set-option -p -t \$TMUX_PANE @role editprompt \
&& #{@editprompt-cmd} open --editor nvim --target-pane #{pane_id} --always-copy" \
'

editpromptのペインは、一度閉じたときにもまた@roleを付与しつつペインが開けるようにしました。

これで、どのペインにいても一発で移動できます。割り当てるキーは、Alt+1とか番号でもいいかなと考え中です。

### ペインをリセット

ペインを1つだけにしたいときに使うレイアウトです。
プロセスもまとめて終了してくれるようなので重宝してます。

presets:
empty:
name: empty
description: プロセス終了用の単一ペイン
command: ""
windowMode: current-window
Terminal window
vde-layout empty

コマンドは入力が面倒なのでvemptyzeno.zshに登録してます。


以上、vde-layoutの使い方の解説でした。何度も同じ操作をしてたのが1キーバインドにまとまってスッキリしました。