Halve the number of whitespace at the begining of each line in Vim

旧城冷巷雨未停 提交于 2019-12-05 15:51:09

The following substitute command inverses the effect of its counterpart doubling leading whitespace.

:%s/^\(\s*\)\1/\1/

A mapping to be constructed for this command needs to follow the same pattern as the one used in the question statement (except for the substitution to execute, of course). To reduce repetition in definitions, one can separate the state-preserving code into a small function:

nnoremap <silent> <leader>>    :call PinnedCursorDo('%s/^\s*/&&/')<cr>
nnoremap <silent> <leader><lt> :call PinnedCursorDo('%s/^\(\s*\)\1/\1/')<cr>
function! PinnedCursorDo(cmd)
    let [s, c] = [@/, getpos('.')]
    exe a:cmd
    let @/ = s
    call setpos('.', c)
endfunction

Your original substitution is this (I have replaced the / delimiters with # for readability):

%s#^\s*#&&#

And here is my proposed inverse substitution (take a deep breath...):

%s#^\s*#\=matchstr(submatch(0),'^.\{'.string(float2nr(len(submatch(0))/2)).'\}')#

Let's say the matched string (submatch(0)) contains n whitespace characters. What I am doing is calculating half this number (n/2 = string(float2nr(len(submatch(0))/2))) and then extracting that many characters from the match (essentially matchstr(n/2)). This ensures we get precisely half the whitespace we started with (which may be a mixture of spaces and tabs).

If you know the whitespace will contain ONLY spaces or ONLY tabs, this could be simplified somewhat, for example:

%s#^\s*#\=repeat(" ",indent(".")/2)#

On another note, I would recommend reformulating your maps to make them more readable and therefore easier to modify and maintain. My approach would be to define two functions:

function! DoubleWS()
    let pos = getpos('.')
    let reg = getreg('@')
    exe '%s/^\s*/&&/e'
    call setreg('@',reg)
    call setpos('.',pos)
endfunction

function! HalfWS()
    let pos = getpos('.')
    let reg = getreg('@')
    exe '%s#^\s*#\=matchstr(submatch(0),"^.\\{".string(float2nr(len(submatch(0))/2))."\}")#e'
    call setreg('@',reg)
    call setpos('.',pos)
endfunction

Note that the get/set pos/reg functions are a much more robust way of maintaining cursor position and register. You can then map these functions as you wish:

nnoremap <silent> <leader>iw :call DoubleWS()<CR>
nnoremap <silent> <leader>rw :call HalfWS()<CR>

Hope that helps!

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!