Vimは便利な機能をたくさん提供している。これまで便利なプラグインについても取り上げているし、本連載で作ってきた設定ファイルを使っているのであれば、すでにVimは多種多様な形式に対応した便利なツールになっているはずだ。しかし、多機能だからこそ逆に不便になることがある。その一つが、オートインデントだ。特にテキストデータを貼り付けるときに自動的にインデントされると、イラ立ちを感じやすい。今回はこのイラ立ちを軽減するショートカット「Ctrl」+「u」について取り上げる。ちょっとしたTIPSだが、知っていると結構便利だ。

オートインデントの功罪

Vimでファイル形式に応じてさまざまな設定を行ってくれるプラグインを導入すると、結構な確率でオートインデントが有効になる。オートインデントとは、その名の通り、自動的にインデントしてくれる機能だ。確かに、XMLやHTML、JSON、または何らかのソースコードを書く場合、インデントは必要不可欠である。オートインデントはそれを補助してくれる機能で、ユーザーが自分でインデントを揃える手間を減らしてくれる。

基本的には便利な機能なのだが(改行すると勝手にカーソルが次にあるべきインデント位置に移動するので、気持ちが悪いと使わない方もいる)、テキストを貼り付ける際には、逆にこの機能がストレスの元になることがある。

テキスト編集というのは常に全く新しいテキストを入力し続けるわけではない。ほかのデータからテキストを持ってきて貼り付けることもあれば、過去のテキストファイルから同じ部分をコピーしてくることもある。こういったケースでは、インデントはあんまり機能してほしくなかったりすることがある。例を見てみよう。

次のスクリーンショットは、XMLファイルを編集しているところだ。カーソルがある次の行にほかのファイルからテキストデータをコピーしていこうとしている。ここでは「o」と入力して下に新しく行を作成して挿入モードへ入っている。「o」ではなく「i↩️」でもよい。

XMLファイルの編集を開始

オートインデントが効いているので、自動的にカーソルがインデントされていることがわかる。

自動的にインデントされている。この状態でシステム機能で貼り付けを実行

ここで貼り付けたいテキストをシステムの提供している貼り付け機能で貼り付けると、次のようになる。

インデントが残念なことになっている

ここではインデントがされていない状態で貼り付けたい。つまり、カーソルが次の位置にある状態で貼り付けを実行したいわけだ。

この状態で貼り付けを実行したい

結果は、次のようになってほしい。

結果としてこんな風になってほしい

こうなると、貼り付けを実行する度に「h」を連打してカーソルを行頭まで移動させがちだ。複数行のテキストを貼り付けるとなると、最初の1行だけがこのオートインデントの罠にはまることになるので、貼り付けた後に最初の1行だけ編集することになり、面倒である。オートインデントを避けようとして、一旦作成した行を「dd」で削除して今度は「O」で作ってみたり「i↩️」や「a↩️」で作ってみたりするのだが、どれもオートインデントの対象となるのでカーソルはインデント位置へ移動してしまう。「ESC」で抜けてから「Ctrl」+「A」でその後「i」という手もあるが、手数が多く、何か釈然としない。

こんなときに便利な操作が、「Ctrl」+「u」だ。

「Ctrl」+「u」からの貼り付け

「Ctrl」+「u」は「カーソルから行頭までを削除する」という処理のショートカットキーだ。例えば、次の状態で「Ctrl」+「u」を押すとする。

この状態で「Ctrl」+「u」を押す

すると、カーソルから行頭までが削除され、この場合は空行になって、カーソルは行頭へ移動する。挿入モードで実行しており、そのまま挿入モードのままだ。このまま貼り付けを実施してみる。

挿入モードのままカーソルが行頭へ移動。ここで貼り付けを実行

すると、次のように想定通りの貼り付け処理が実施されるわけである。

想定通りの貼り付け処理が完了

プラグインによっては貼り付けたテキストを解析してそちらをオートインデントするので、ここで取り上げたような問題が発生しないこともある。

しかし、この「『Ctrl』+『u』でカーソルから行頭までを削除」というのは知っておくと便利なショートカットキーだ。「Ctrl」+「u」というショートカットキーの説明だけを見ると、「行頭まで削除する処理に、使い道があるのだろうか」と思うかもしれないが、実際にはこんな感じでぴったりの用途が存在している。

なお、「Ctrl」+「u」の逆は「Ctrl」+「k」だ。「Ctrl」+「k」でカーソルから行末までが削除される。こちらも知っておくと便利なので、合わせて覚えておこう。

付録: 使っている設定ファイルとセットアップ方法

プラグインを使うためにDeinをセットアップする方法

mkdir -p ~/.cache/dein
cd ~/.cache/dein/
curl https://raw.githubusercontent.com/Shougo/dein.vim/master/bin/installer.sh > installer.sh
sh ./installer.sh .
rm ./installer.sh

本連載で使っている~/.vimrcファイル

"dein Scripts=============================
if &compatible
  set nocompatible               " Be iMproved
endif

" Required:
set runtimepath+=~/.cache/dein/./repos/github.com/Shougo/dein.vim

" Required:
if dein#load_state('~/.cache/dein/.')
  call dein#begin('~/.cache/dein/.')

  " Let dein manage dein
  " Required:
  call dein#add('~/.cache/dein/./repos/github.com/Shougo/dein.vim')

  " Add or remove your plugins here
  call dein#add('junegunn/seoul256.vim')
  call dein#add('vim-airline/vim-airline')
  call dein#add('vim-airline/vim-airline-themes')
  call dein#add('preservim/nerdtree')
  call dein#add('tpope/vim-commentary')
  call dein#add('tpope/vim-fugitive')
  call dein#add('fholgado/minibufexpl.vim')
  call dein#add('dense-analysis/ale')
  call dein#add('junegunn/fzf', {'build': './install --all'})
  call dein#add('junegunn/fzf.vim')
  call dein#add('sheerun/vim-polyglot')
  call dein#add('junegunn/vim-easy-align')

  " Required:
  call dein#end()
  call dein#save_state()
endif

" Required:
filetype plugin indent on
syntax enable

" If you want to install not installed plugins on startup.
if dein#check_install()
  call dein#install()
endif

" seoul256
let g:seoul256_background = 233
colo seoul256

" vim-airline
let g:airline_powerline_fonts = 1
let g:airline_theme = 'molokai'

" NERDTree
"  <C-o> open NERDTree
nnoremap <silent> <C-o> :NERDTreeToggle<CR>

" minibufexpl
nnoremap <silent> bn :<C-u>:bnext<CR>
nnoremap <silent> b1 :<C-u>:b1<CR>
nnoremap <silent> b2 :<C-u>:b2<CR>
nnoremap <silent> b3 :<C-u>:b3<CR>
nnoremap <silent> b4 :<C-u>:b4<CR>
nnoremap <silent> b5 :<C-u>:b5<CR>
nnoremap <silent> b6 :<C-u>:b6<CR>
nnoremap <silent> b7 :<C-u>:b7<CR>
nnoremap <silent> b8 :<C-u>:b8<CR>
nnoremap <silent> b9 :<C-u>:b9<CR>

" fzf
nnoremap <silent> fzf :Files<CR>
nnoremap <silent> ls :Buffers<CR>

" vim-easy-align
xmap ga <Plug>(EasyAlign)
nmap ga <Plug>(EasyAlign)

"End dein Scripts=========================

set number
syntax on
set whichwrap=b,s,[,],<,>,~,h,l
set cursorline
set incsearch
set hlsearch
set ignorecase
nnoremap k gk
nnoremap gk k
nnoremap j gj
nnoremap gj j
nnoremap q b
vnoremap q b
nnoremap <Tab> 15<Right>
nnoremap <S-Tab> 15<Left>
nnoremap vis ?\(。\\|\.\\|^$\\|>\)<CR>lv/\(。\\|\.\\|^$\\|<\\|:\)<CR>
nnoremap >< /<\([^>/]\+\)><\/\1><CR>/<<CR>
nnoremap <> ?<<CR>h?<\([^>/]\+\)><\/\1><CR>/<<CR>
nnoremap ( ?\(。\\|、\\|[.:][ \t\n]\)<CR>h?\(。\\|、\\|[.:][ \t\n]\)<CR>l
vnoremap ( hh?\(。\\|、\\|[.:][ \t\n]\)<CR>l
nnoremap ) /\(。\\|、\\|[.:][ \t\n]\\|^\n\)<CR>l
vnoremap ) /\(。\\|、\\|[.:][ \t\n]\\|^\n\)<CR>
nnoremap "" /""<CR>l
nnoremap '' /''<CR>l
nnoremap :: hh?""<CR>l
nnoremap ;; hh?''<CR>l
nnoremap <C-a> <Home>
inoremap <C-a> <Home>
cnoremap <C-a> <Home>
vnoremap <C-a> <Home>
nnoremap <C-e> <End>
inoremap <C-e> <End>
cnoremap <C-e> <End>
vnoremap <C-e> <End>