rcmdnk's blog

モナドの領域 | 筒井 康隆 | 日本の小説・文芸 | Kindleストア | Amazon

普段ターミナル上ではGNU screenを立ち上げてその中で いくつかウィンドウを立ち上げて作業を行っています。

その際用いるエディタはVimです。

どちらも内部で複数のウィンドウを同時に表示出来るような画面分割の機能がありますが、 その辺の使い分けや設定についてちょっとまとめてみました。

GNU screen + Vim

Tmux and Vim - even better together というポストについて Hacker News で盛り上がってたので、 Tmuxに変わってGNU screenについて、 ちょっと方向性は違いますが自分設定をまとめてみたいと思います。

TmuxとGNU screenの違いなどについては以下を参照。

Vim

.vimrc はGitHubにあるdotfilesレポジトリにあります。

領域分割、削除、バッファ削除

領域分割はデフォルトキーのまま、

  • Ctrl-W (Ctrl-)S: 横分割
  • :vs [file]: 横分割
  • Ctrl-W (Ctrl-)V: 縦分割
  • :sp [file]: 横分割

等。

領域の削除などについてはこんな感じのマッピングを使っています。

.vimrc
1
2
3
4
5
6
7
8
9
10
" don't enter Ex mode: map to quit
nnoremap Q :q<CR>
" Use other one characters
nnoremap Z ZZ
nnoremap W :w<CR>
nnoremap ! :q!<CR>

" Close/Close & Save buffer
nnoremap <Leader>q :bdelete<CR>
nnoremap <Leader>w :w<CR>:bdelete<CR>

QはデフォルトでExモードに入るキーですが、 Exモードを使う機会が無いので(というより使ったことが無いので)。

通常の終了等は:qとかを打っても余り変わりないと思いますが、 bdeleteとかしたい場合には何らかのマッピングをしておくと便利だと思います。

領域間移動

領域移動もデフォルトのまま

  • Ctrl-W (Ctrl-)H: 左
  • Ctrl-W (Ctrl-)J: 下
  • Ctrl-W (Ctrl-)K: 上
  • Ctrl-W (Ctrl-)L: 右

領域の幅の変更

領域の幅の変更を連続的に行うため、 kana/vim-submode というプラグインを使っています。

.vimrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
call submode#enter_with('winsize', 'n', '', '<C-w>>', '<C-w>>')
call submode#enter_with('winsize', 'n', '', '<C-w><', '<C-w><')
call submode#enter_with('winsize', 'n', '', '<C-w>+', '<C-w>+')
call submode#enter_with('winsize', 'n', '', '<C-w>-', '<C-w>-')
call submode#enter_with('winsize', 'n', '', '<C-w>e', '<C-w>><C-w><')
call submode#enter_with('winsize', 'n', '', '<C-w><C-e>', '<C-w>><C-w><')
call submode#map('winsize', 'n', '', '>', '<C-w>>')
call submode#map('winsize', 'n', '', '<', '<C-w><')
call submode#map('winsize', 'n', '', '+', '<C-w>-')
call submode#map('winsize', 'n', '', '-', '<C-w>+')
call submode#map('winsize', 'n', '', 'l', '<C-w>>')
call submode#map('winsize', 'n', '', 'h', '<C-w><')
call submode#map('winsize', 'n', '', 'j', '<C-w>-')
call submode#map('winsize', 'n', '', 'k', '<C-w>+')
call submode#map('winsize', 'n', '', '<C-l>', '<C-w>>')
call submode#map('winsize', 'n', '', '<C-h>', '<C-w><')
call submode#map('winsize', 'n', '', '<C-j>', '<C-w>-')
call submode#map('winsize', 'n', '', '<C-k>', '<C-w>+')
call submode#map('winsize', 'n', '', '=', '<C-w>=')
call submode#map('winsize', 'n', '', '<C-=>', '<C-w>=')

細かい説明は下の作者のブログに詳しいですが、 Ctrl-W Ctrl-E(もしくは><+-) で領域変更(winsize)モードに入り、 後はhjklを押すだけで領域の大きさが変更できます。

submode.vim とその設定例なんかを紹介 - 永遠に未完成

以下には変更時のGif画像があります。

ちょっとあれなのは、 例えばH領域を横に伸ばす、なので 左上の領域だと右に伸びていって直感道理ですが 右の領域でやると逆に伸びてく感じになります。

同様に上下の伸び縮みも上側の領域での感覚になります。

ただこれは結構便利でおすすめの設定です。

GNU screen

.screenrc.vimrc同様GitHubにあります。

またscreenの起動コマンドのラッパーコマンドなどの設定を .bashrcから読み込むための setup.sh や、中でのレイアウト作成などに使うスクリプトが .screen にあります。

領域分割

.screenrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Escape (Prefix)
escape ^Qq

# Split
bind v split -v
bind V split -v
bind ^v split -v
bind s split
bind S split # default
bind ^s split

# Remove window region
bind x remove
bind X remove # default

# Make 4 window with no new screen
# First 'next' is needed when it is on empty window for exec
bind r eval 'next' 'exec /bin/sh -c ~/.screen/layout.sh'
bind ^r eval 'next' 'exec /bin/sh -c ~/.screen/layout.sh'

# Only
bind Q only # default
bind q only

SVshiftCtrl付きの時を含め 水平分割と垂直分割に割り当てています。

大概の場合Ctrl-Q Ctrl-V(screenのEscape(Prefix)はQに設定) の様な感じでPrefixの時のCtrlを押したままなので^vとかだけでも良いのですが 下手に他のものに割り当ててあると間違うときがあるので一応。

これらはVimで Ctrl-Wを使った方法と同じ様な入力になります。

また、最初に入力するキーもWQの違いで隣同士なので左手で似たような感覚で打てます。

領域削除はデフォルトShift-Xですが、Shift無しの場合も削除に割り当てています。 こちらのデフォルトはlockscreenでまず使う事が無いので。

また、殆どの場合、ターミナルを大きな表示にしてそれを縦横4分割にして使っています。 その分割に一瞬で出来る様なスクリプトがleyout.shRで呼び出せる様にしています。

layout.shの内容はGitHubで。

dotfiles/layout.sh at master · rcmdnk/dotfiles

色々やってますが、重要な所は

screen -X source $HOME/.screen/${name}.layout >>$log 2>&1

をやっている所で、ここでnameはデフォルト4-windowsでそのファイルは

$HOME/.screen/4-windows.layout
1
2
3
4
5
6
7
8
9
10
11
12
only
select $win0
split
split -v
focus
select $win1
focus
select $win2
split -v
focus
select $win3
focus

こんな内容のscreenのコマンド群に。これを外部からscreenのセッションに送ってあげてるわけです。

最初にまずonlyで1つの画面に戻して、横分割縦分割などを繰り返して4つの領域にして それぞれで違うウィンドウを順に選んでいます。

$win0とかは0とか1とかが入っていますが、 layout.shの中で呼んでいる win_prepare.sh の中で見つかったウィンドウの番号を順に詰めています。

この辺について、もうちょっと詳しい話や screenのレイアウト機能を使った話は以下を参照してください。

最後に、現在使ってるウィンドウだけの表示にしたい時、 onlyがデフォルトでShift-Qにアサインされてますが、 小文字の場合もあてています。 小文字の方はデフォルトxon(Send a control-q to the current window)になっていますが、 むしろそんなことをされても困るので間違ってもxonをしないように。

そうでなくても結構使うコマンドなので、Shiftを押すのはちょっと面倒ということもあり。

ウィンドウ生成、削除、入れ替え

.screenrc
1
2
3
4
5
6
7
8
9
10
11
12
# new window
bind c c # default
bind c ^c # default

# kill
bind K kill

# exchange
bind n eval 'next' # default
bind ^n eval 'next' # default
bind p eval 'prev' # default
bind ^p eval 'prev' # default

新規ウィンドウの作成はデフォルトのままCを使っています。

ウィンドウの削除は通常はそのウィンドウでの作業をexitで終了させて 終わりにさせますが、 コマンドとしてはShift-Kをあてています。 削除のデフォルトキーはShift無しのKですが、 下に各様に領域移動に使うためです。

ウィンドウの入れ替えに付いては 特にtmuxと違う部分でscreenの特徴的なところですが、 これらのキーバインドはデフォルトのままでいい感じなのでそのままに。

これに関して、

.screenrc
1
2
3
4
5
6
7
# Continuous window change
bind ^n eval 'command -c window' 'next'
bind ^p eval 'command -c window' 'prev'
bind -c window n eval 'next'
bind -c window p eval 'prev'
bind -c window ^n eval 'command -c window' 'next'
bind -c window ^p eval 'command -c window' 'prev'

の様な設定をすると、Prefixキーを最初に一回押すだけで後はCtrl-Nを押し続けるだけで次のウィンドウに どんどん切り替えていく、という設定をすることが出来ます。

commandを使うと-cで指定したクラス(ここではmove)に属すキー(bind -c moveで指定されたキー)を 次にPrefix無しで受け付けてくれるからです。

ただ、これを設定してしまうと 必ずキー入力待ち状態になるので切り替え後にコマンドを打とうと思って 入力した時に最初の文字が入らずにちょっとイラッと来ます。

これを解消するために、Ctrlなしの場合はcommand -c windowを呼ばない設定にしておいて 最後にそれを使えばすぐに入力できる、と言った状態にもしてみましたが どうもしっくりきませんでした。

ということで現在はこの設定は無効化してあります。

領域間移動

.screenrc
1
2
3
4
5
6
7
8
9
10
11
# Focus (like vi)
bind h  eval     'focus left'
bind j  eval     'focus down'
bind k  eval     'focus up'
bind l  eval     'focus right'
bind ^h eval     'focus left'
bind -k kb eval  'focus left' #Backspace
#bind \015  eval 'focus down' #Enter
bind ^j eval     'focus down'
bind ^k eval     'focus up'
bind ^l eval     'focus right'

分割した領域は縦横 VimのCtrl-W Hなどと同様の感覚で移動できる様に設定しています。

これもCtrlを押したまま押しても大丈夫なようにしていますが、 Ctrl-hCtrl-Jと言った、 BackspaceEnterに対応するようなキーも入っているため 単純な設定だと上手く動かないときがあります。

今の設定ではBackspaceキーも直接左移動に割り当てています 。 Enterの方は前に^jで上手く動かない環境があったのですが、 今使ってる環境の中ではどれも動くので\015(Enter)のキー割り当てはしてません。

これに関してもウィンドウ切り替え同様、 以下の様な設定をすると 一度Ctrl付きの移動キーを押した後、その後Prefixキーの入力なしで移動出来る様になります。

.screenrc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
bind h  eval    'focus left'
bind j  eval    'focus down'
bind k  eval    'focus up'
bind l  eval    'focus right'
bind ^h eval    'command -c move' 'focus left'
bind -k kb eval 'command -c move' 'focus left' #Backspace
bind ^j eval    'command -c move' 'focus down'
bind ^k eval    'command -c move' 'focus up'
bind ^l eval    'command -c move' 'focus right'

bind -c move h eval     'focus left'
bind -c move j eval     'focus down'
bind -c move k eval     'focus up'
bind -c move l eval     'focus right'
bind -c move ^h eval    'command -c move' 'focus left'
bind -c move -k kb eval 'command -c move' 'focus left' #Backspace
bind -c move ^j eval    'command -c move' 'focus down'
bind -c move ^k eval    'command -c move' 'focus up'
bind -c move ^l eval    'command -c move' 'focus right'

沢山領域分割していて移動したいときなんかはとても便利かと。

ただ、今は多くて2個(右下など)なのと やはり移動後に一回入力出来ないのが良くないので有効にしていません。

screenで分割した他の領域で開いてるVimへ行って Vimの中でさらに移動したい時は

Ctrl-Q (Ctrl-)L Ctrl-W (Ctrl-)J

など。。。流石にたまに混乱します。

領域の幅の変更

.screenrc
1
2
3
4
5
6
7
8
9
10
11
# Resize window
bind e eval 'command -c resize' 'echo "Resize window"'
bind ^e eval 'command -c resize' 'echo "Resize window"'
bind -c resize h eval 'command -c resize' 'resize -h -1'
bind -c resize l eval 'command -c resize' 'resize -h +1'
bind -c resize j eval 'command -c resize' 'resize -v +1'
bind -c resize k eval 'command -c resize' 'resize -v -1'
bind -c resize ^h eval 'command -c resize' 'resize -h -1'
bind -c resize ^l eval 'command -c resize' 'resize -h +1'
bind -c resize ^j eval 'command -c resize' 'resize -v +1'
bind -c resize ^k eval 'command -c resize' 'resize -v -1'

ここではcommandを使っています。 Ctrl-Q Eresizeモードに入って hjklで現在の領域を伸び縮みさせます。

commandを使っているので連続的に伸び縮みさせてちょうどよい所で Escなり適当な他のキーを押せば止まります。

この操作に関してはすぐに入力をしたい感じではないので良いかと。

この設定もVimでの領域変更とPrefixが違うだけで同じ様に出来るようにしています。

コピーモード

ちょっとウィンドウ操作からは離れますが、 GNU screenにはコピーモードという、ターミナルに表示された 履歴をキーボードのみでコピーできるモードがありますが、 screenではこの中での操作はデフォルトでVimライクなものになります。

開発版GNU Screenでコピペを極める - Keep It Simple, Stupid

Emacsライクにするにはキーバインドの設定で行います。

一方、Tmuxはviモードも設定で簡単に出来ますが、デフォルトはEmacsモードになっています。

ついでにコピーモードの代わりにスクロールバッファをVimにぶちこんで見る、というのも見つけたので リンクを張っておこうかと。

GNU screenのスクロールバッファをvimで開いて、コピーモードのかわりに使う方法 - Qiita

まとめ

GNU screen、Vim共に領域を分割することが出来るアプリケーションですが、 領域の作成や移動などを似たようなものにしています。 (主にscreenでの操作をVimに真似てる)

共通の動作をまとめると:

  • Prefix (Ctrl-)S: 横分割
  • Prefix (Ctrl-)V: 縦分割
  • Prefix (Ctrl-)H: 左移動
  • Prefix (Ctrl-)J: 下移動
  • Prefix (Ctrl-)K: 上移動
  • Prefix (Ctrl-)L: 右移動
  • Prefix (Ctrl-)E: 領域変更モード
    • Ctrl-)H: 横方向拡大
    • Ctrl-)J: 縦方向拡大
    • Ctrl-)K: 縦方向縮小
    • Ctrl-)L: 横方向縮小

といった感じ。VimではPrefixはCtrl-W、 screenでのPrefix(escape)はCtrl-Q

似たようなものだと逆に混乱することもあるにはありますが その辺は慣れで。 ぜんぜん違うものにしておくよりは慣れれば楽なはずです。

おまけ: その他GNU screen/Vimについての過去記事

/blog/tags/screen/

/blog/tags/vim/

Sponsored Links
Sponsored Links

« Firefox 53 リリース: タブバーなどをコンパクトに出来るデフォルトテーマが追加 GitHubのAPIのリクエスト制限を避けるためにclient idなどを取得する »

}