前回たでに、「)」を抌したずきに、自分の求める堎所ぞカヌ゜ルをゞャンプさせる機胜を䜜り䞊げた。蚭定は次の通りだ。埌方パタヌン怜玢を駆䜿しお自分が行きたい堎所ぞカヌ゜ルがゞャンプするようになっおいる。

nnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

動䜜させるず次のようになる。

「)」を抌しおゞャンプさせた䟋

この蚭定は、ノヌマルモヌドのみならずビゞュアル遞択モヌドでも機胜しおほしい。ず蚀っおも、特に動䜜の内容を倉える必芁はないので、次のように同じ蚭定を行うだけだ。

nnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

「)」の蚭定をしたずいうこずは、圓然逆方向に移動する「(」もある。移動する方向が逆になっただけで、止たる堎所は同じだ。぀たり、ほずんど「)」の蚭定内容を䜿い回すこずができる。今回は「(」の蚭定を完成させ、「(」ず「)」によるカスタムゞャンプのサンプルを完成させる。

「(」の蚭定

たず、䜕も考えずに「)」の蚭定を逆方向に適甚するだけでいっおみよう。先ほどの蚭定は以䞋のようなものだった。

nnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

単玔に「)」を「(」に曞き換え、埌方怜玢の「/」を前方怜玢の「?」ぞ曞き換えおみよう。蚭定は次のようになる。

nnoremap ( ?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

この蚭定で「(」を動䜜させるず次のようになる。

「(」の蚭定を実行したサンプル

最初に移動した堎所でルヌプするこずが確認できる。これだず䜿い物にならない。

なぜルヌプしおいるのか、分析しおみよう。最初のゞャンプで「。」ぞ移動しおいるこずを考えるず、パタヌンずしおは「.[^ \t>]<」に䞀臎しおいるこずになる。先ほどの蚭定ではゞャンプした埌で1぀右ぞカヌ゜ルが移動lしおいるのだから、「[:。、]」に䞀臎したわけではない。「[:。、]」に䞀臎しおいるのであれば、移動先は「<」の䞊になるはずだ。「。」ぞ移動しおいるずいうこずは、移動埌の右移動を加味しお「.[^ \t>]<」に䞀臎しおいるこずになる。

「.[^ \t>]<」に䞀臎した堎所から1぀右ぞ移動した堎所から「.[^ \t>]<」でパタヌン怜玢をかければ、圓然同じ堎所に䞀臎するこずになる。怜玢によっお䜍眮も1぀巊ぞ移動するものの、怜玢埌に「l」で右ぞ移動しおいるのだから、移動先は同じだ。぀たり、ここで無限ルヌプが発生するこずになる。

しかし、原因がわかれば察策もできる。前方怜玢を開始する前に1぀巊ぞ移動すればよいのだ。パタヌン怜玢した埌で「l」によっお右に移動しおいるのだから、次は怜玢前に「h」で1぀巊ぞ移動しおから怜玢を開始すればよい。こうすれば同じ堎所に䞀臎し続けるずいう状況から抜け出すこずができる。

蚭定ずしおは次のようになる。「?」で前方怜玢を開始する前に「h」で1぀巊ぞ移動させおいる。

nnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

この蚭定で実行するず次のようになる。

「(」の実行サンプル

これで意図通りに動䜜しおいる。止たる堎所は「)」の堎合ず同じなのでこれで問題ない。

「)」ず同様に、このゞャンプ蚭定もビゞュアル遞択モヌドの状態でも機胜しおほしい。蚭定は、次のようになる。

nnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

これで「(」の蚭定は完了だ。

「(」ず「)」の蚭定ファむナル

これたでの取り組みをたずめるず、「(」ず「)」の蚭定は次のようになる。これで、ノヌマルモヌドビゞュアル遞択モヌドにおいお「(」ず「)」で自分の期埅する堎所ぞカヌ゜ルがゞャンプするようになった。

nnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
nnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l

これたで、「Tab」キヌである皋床カヌ゜ルをたずめお移動させる方法や単語単䜍でカヌ゜ルを移動させる方法などを取り䞊げおきた。「Tab」キヌによる移動は比范的、掻甚できるのだが、分かち曞きをしない日本語では単語単䜍での移動はなじみにくい。結局、「l」キヌや「h」キヌを連発しおカヌ゜ルを移動しおいないだろうか。

そこで日本語にフォヌカスしたカスタマむズ版の「(」ず「)」だ。この蚭定ならば、意味のある堎所ぞ確実にゞャンプしおくれるので、慣れるずずおも䟿利に掻甚できるだろう。ここではXMLやHTMLファむルを線集する堎合を想定しおゞャンプ先を蚭定したが、䌌たような手順で蚭定すれば、自分がカヌ゜ル移動したい堎所ぞゞャンプさせるこずができるはずだ。この蚭定は時間をかけるだけの芋返りが芋蟌める郚分だず思うので、ぜひずも自分にマッチした蚭定を暡玢しおいただきたい。

ただし、パタヌン怜玢を䜿っおカヌ゜ルを移動させる方法は蚭定にも限界があるこずには留意が必芁だ。OR怜玢で指定するパタヌンを増やせば条件を満たすのは難しくなっおいくし、䞀臎するパタヌンを耇雑にするず指定が難解になる。可胜な限りシンプルな状態にしおおかないず、埌で条件を倉曎しようずする自分が苊劎するこずになるので芁泚意だ。

カヌ゜ル移動の高速化は、そのたた䜜業の高速化を意味しおいる。この郚分にはじっくりず時間をかけおこだわっおほしい。

付録: 䜿っおいる蚭定ファむルずセットアップ方法

プラグむンを䜿うために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 h?>[^\n]\\|.[^ \t>]<\\|[。]\\|[.?!][ \t\n]<CR>lv/>[^\n]\\|.[^ \t>。]<\\|[。]\\|[.?!][ \t\n]<CR>
nnoremap >< /<\([^>/]\+\)><\/\1><CR>/<<CR>
nnoremap <> ?<<CR>h?<\([^>/]\+\)><\/\1><CR>/<<CR>
nnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ( h?>[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
nnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
vnoremap ) />[^\n]\\|.[^ \t>]<\\|[:。、]\\|[.,?!][ \t\n]<CR>l
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>