" Remap i{",',`} and a{",',`} to search for the next string. This is more like how objects like i( and i{ work. " " The behavior inside the quotes should remain unchanged. onoremap i" call find_quote('i', '"') onoremap a" call find_quote('a', '"') onoremap i' call find_quote('i', "'") onoremap a' call find_quote('a', "'") onoremap i` call find_quote('i', '`') onoremap a` call find_quote('a', '`') vnoremap i" call find_quote('i', '"') vnoremap a" call find_quote('a', '"') vnoremap i' call find_quote('i', "'") vnoremap a' call find_quote('a', "'") vnoremap i` call find_quote('i', '`') vnoremap a` call find_quote('a', '`') function! s:find_quote(ai, q) abort let l = getline('.')[:col('.') - 2] let cnt = 0 let skip = 0 for c in l if c ==# a:q && !skip let cnt = !cnt endif if c ==# '\' let skip = 1 else let skip = 0 endif endfor let flags = 'W' if cnt == 1 let flags .= 'b' endif exec "normal! \" call search(a:q . '\zs.', flags) exec "normal! v" . a:ai . a:q endfunction " Fix silly yank behavior. nnoremap Y y$ " . in visual mode will replay the last command on each line in the visual mode. vnoremap . call visual_repeat() function! s:visual_repeat() exec "normal! \" let [_, _, c, _] = getpos('.') let [b, l1_, _, p] = getpos("'<") let [_, l2_, _, _] = getpos("'>") let l1 = min([l1_, l2_]) let l2 = max([l1_, l2_]) let l = l1 while l <= l2 let newpos = [b, l, c, p] call setpos('.', newpos) if newpos == getpos('.') " Only execute if the new position was valid. normal! . endif let l += 1 endwhile endfunction