ターミナルで vim を開き、外部からコードや設定ファイルを貼り付けたとき、インデントが1行ごとにずれて階段状になることがあります。コマンドラインで頻繁に作業する場合によく遭遇する現象です。原因と対処法を順に説明します。
字下げが階段状になる原因
vim には autoindent(および smartindent)という設定があります。これは直前の行のインデント量を次の行に引き継ぐ機能で、コードを手で書くときの利便性を高めます。
問題はターミナルエミュレータ経由でテキストを貼り付けるときに起きます。gnome-terminal や iTerm2、SSH 越しのターミナルなどは、クリップボードの内容を「キーストロークの連続」として vim に送り込みます。vim 側からは、ユーザーが1文字ずつ手入力したのか、クリップボードから貼り付けたのかを区別できません。そのため、貼り付け文字列に含まれる改行が届くたびに autoindent が働き、インデントが1段ずつ加算されていきます。
結果として、元は揃っていたインデントが次のように崩れます。
if condition:
do_something()
do_another()
do_more()
これは vim 固有の問題で、autoindent や関連する自動補完機能が有効になっているほど崩れ方が大きくなります。
その場で直す方法
貼り付け前に vim のノーマルモードで次のコマンドを実行します。
:set paste
このコマンドを実行すると、autoindent や smartindent、各種キーマッピングが一時的に無効になり、受け取ったテキストをそのまま流し込む「ペーストモード」に切り替わります。ステータスラインに -- INSERT (paste) -- と表示されている間がペーストモードです。
貼り付けが終わったら次のコマンドで元の状態に戻します。
:set nopaste
nopaste に戻さないとキーマッピングが効かないままになります。貼り付け後は必ず元に戻す習慣をつけると安全です。
キーに割り当てて切り替える(pastetoggle)
毎回2つのコマンドを打つのが手間な場合は、pastetoggle にキーを割り当てると素早く切り替えられます。次のコマンドで F2 キーに割り当てられます。
:set pastetoggle=<F2>
これで F2 を押すたびにペーストモードのオン・オフが切り替わります。
.vimrc に書いて毎回の手間をなくす
pastetoggle の設定は ~/.vimrc に書いておくと、vim 起動時から常に有効になります。
set pastetoggle=<F2>
autoindent 自体を無効にする方法(set noautoindent)もありますが、コーディングには不便になることが多いため、ペーストモードの切り替えで運用するほうが一般的です。
bracketed paste mode を使う方法
vim 8.0 以降と対応したターミナルエミュレータの組み合わせでは、bracketed paste mode が利用できます。これはターミナルエミュレータがクリップボード貼り付けの開始と終了をエスケープシーケンスで通知し、vim 側がペーストモードを自動で切り替える仕組みです。~/.vimrc に次を追加することで有効化できます。
if &term =~ "xterm"
let &t_BE = "\e[?2004h"
let &t_BD = "\e[?2004l"
exec "set t_PS=\e[200~"
exec "set t_PE=\e[201~"
endif
ただし SSH 越しや tmux・screen などのターミナルマルチプレクサ経由ではエスケープシーケンスが途中で失われることがあります。環境によっては機能しないケースもあるため、うまくいかない場合は :set paste による手動切り替えが確実です。
nano での挙動
nano はバージョン 2.9.8 以降、デフォルトで bracketed paste mode に対応しています。多くの現行ディストリビューションに同梱されているバージョンであれば、特別な設定をしなくても貼り付けた内容がそのまま挿入されます。バージョンは次のコマンドで確認できます。
nano --version
古い nano で階段状になる場合、xclip や xsel を使って標準入力経由で流し込む方法が代替になります。ただしこの方法は既存ファイルをその場で編集する操作ではなく、用途が限られます。
よくあるつまずき
`:set paste` にしたのにずれが直らない
挿入モードに入った状態で :set paste を実行しようとしているケースがよくあります。:set paste はノーマルモード(Esc キーで戻る)で実行し、その後 i で挿入モードに入ってから貼り付けてください。
SSH 越しでだけ発生する
ローカルのターミナルとリモートの vim の間でエスケープシーケンスが失われることがあります。bracketed paste mode の自動設定が機能しない場合でも、:set paste による手動切り替えは SSH 越しでも有効です。
tmux 経由でだけ発生する
tmux がデフォルト設定で bracketed paste mode のエスケープシーケンスをフィルタリングしていることがあります。tmux 側の設定を調整する方法もありますが、複雑になりやすいため、vim の :set paste で対処するほうがシンプルです。
貼り付け後にキーバインドが効かなくなった:set paste にしたまま nopaste に戻し忘れているケースです。:set nopaste を実行するか、pastetoggle に割り当てたキーを押して元に戻してください。現在のモードは :set paste? で確認できます。
「コマンドは打てる。次は”現場で通用する型”を最短で身につけたい」——そんなあなたへ。
ネットの断片的なTipsをコピペするだけでは、体系的な運用スキルはなかなか積み上がりません。リナックスマスター.JPの無料メルマガ「リナマガ」では、現場で実際に使うLinuxサーバー運用の考え方を、順を追って実務目線でお届けしています。いま登録された方には、安全なサーバー構築の「型」をまとめた『Linuxサーバー構築入門マニュアル(図解60P)』を完全無料でプレゼント中です。
>> 図解60P『Linux入門マニュアル』を無料で受け取る
(メルマガ登録は10秒・いつでも解除OK)
※ 「独学の時間がもったいない」「プロから現場の技術を最短で学びたい」という本気の方には、2日で実務レベルが身につく初心者向けハンズオンセミナーもご用意しています。
