I'd count the number of space characters before the cursor at the moment <cr>
is hit and produce as many <BS>
. It can be done with substitute
:
:inoremap <expr> <cr> substitute(matchstr(getline('.')[: col('.')-2], '\S\zs\s*$'), '.', "<bs>", 'g')."<cr>"
or with repeat
+len
:
:inoremap <expr> <cr> repeat("<bs>", len(matchstr(getline('.')[: col('.')-2], '\S\zs\s*$')))."<cr>"
Notes:
- As there is no movement/break (with
<esc>
) in the flow of this solution, anything that is typed can be undone, redone , etc. However, if you start a new insert sequence to cut after a series of spaces, redoing the same insertion sequence with.
elsewhere is likely to remove too many characters. - The
\S\zs
is a workaround when we're on en empty line and when each<BS>
deletes&sw
characters. In that case I should checkgetline()
result and do something smarter.
A version that behaves a little bit better regarding indented empty lines is the following:
function! s:trim_ws_on_the_fly()
let line = getline('.')
" TODO: set and reset &bs
if line =~ '^\s*$'
let nb = (virtcol('.') + 2*&sw-2) / &sw - 1
" echomsg "remove "virtcol('.').'/'.&sw.' -> '.nb
else
let nb = len(matchstr(line[: col('.')-2], '\s*$'))
let line = ''
endif
return repeat("\<bs>", nb)."\<cr>".line
endfunction
inoremap <expr> <cr> <sid>trim_ws_on_the_fly()