Skip to content

Instantly share code, notes, and snippets.

@olmokramer
Last active September 9, 2019 20:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save olmokramer/ae6a522d667abb2ae86ad3b133aba8d4 to your computer and use it in GitHub Desktop.
Save olmokramer/ae6a522d667abb2ae86ad3b133aba8d4 to your computer and use it in GitHub Desktop.
Vim delete mode
" ~/.vim/vimrc
nmap <Leader>D <Plug>(delete-mode-start)
" ~/.vim/autoload/delete_mode.vim
" Known issues:
"
" - When you quit delete mode by an invalid motion or text object, such as `x`,
" and then immediately perform a change, delete mode is entered again.
" - Relies on the order of execution of TextChanged and CursorMoved autocommand
" events.
if !exists('s:save_maps')
let s:save_maps = {}
endif
function! s:save_map(lhs, mode) abort
let s:save_maps[a:lhs] = maparg(a:lhs, a:mode, 0, 1)
endfunction
function! s:restore_map(lhs) abort
let m = get(s:save_maps, a:lhs, '')
if !empty(m)
execute printf(
\ '%s%smap%s %s%s%s %s %s',
\ m.mode == '!' ? '' : m.mode,
\ m.noremap ? 'nore' : '',
\ m.mode == '!' ? '!' : '',
\ m.silent ? '<silent>' : '',
\ m.expr ? '<expr>' : '',
\ m.buffer ? '<buffer>' : '',
\ m.lhs,
\ m.rhs,
\ )
endif
endfunction
function! delete_mode#operatorfunc(type) abort
if a:type == 'char'
normal! `[v`]
elseif a:type == 'line'
normal! '[V']
elseif a:type == 'block'
normal! `[<C-v>`]
else
normal! gv
endif
execute 'normal! "' . toupper(s:register) . 'd'
endfunction
function! s:main() abort
let s:text_changed = 1
echo '-- DELETE --'
redraw
set operatorfunc=delete_mode#operatorfunc
call feedkeys('g@', 'n')
endfunction
function! s:stop() abort
autocmd! delete_mode
augroup! delete_mode
ounmap <buffer> <Esc>
ounmap <buffer> <C-c>
call s:restore_map('<Esc>')
call s:restore_map('<C-c>')
echo
redraw
endfunction
function! s:maybe_stop() abort
let s:text_changed = 0
call timer_start(0, { _ -> s:text_changed ? 0 : s:stop() })
endfunction
function! delete_mode#stop() abort
call s:stop()
endfunction
function! delete_mode#start() abort
let s:register = v:register
call setreg(s:register, '')
augroup delete_mode
autocmd!
autocmd TextChanged <buffer> call <SID>main()
autocmd CursorMoved <buffer> call <SID>maybe_stop()
autocmd InsertEnter <buffer> call <SID>stop()
autocmd BufWinLeave <buffer> call <SID>stop()
autocmd WinLeave <buffer> call <SID>stop()
augroup END
call s:save_map('<Esc>', 'o')
call s:save_map('<C-c>', 'o')
omap <buffer> <Esc> <Plug>(delete-mode-stop)
omap <buffer> <C-c> <Plug>(delete-mode-stop)
call s:main()
endfunction
" ~/.vim/plugin/delete_mode.vim
nnoremap <Plug>(delete-mode-start) :<C-u>call delete_mode#start()<CR>
onoremap <Plug>(delete-mode-stop) <Esc>:<C-u>call delete_mode#stop()<CR>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment