Reduce the number of spaces at the beginning of each line in Vim

Can someone tell me how to do the opposite of this mapping in Vim:

nnoremap <leader>iw :let _s=@ /<Bar>:let _s2=line(".")<Bar>:%s/^\s*/&&/ge<Bar>:let @/=_s<Bar>:nohl<Bar>exe ':'._s2<CR> 

As an explanation, this collation doubles ( && part) the number of spaces at the beginning of each line. Only spaces appear before the first regular character. The current search string is saved (variable _s ). The position is restored after this conversion (variable _s2 )

So, basically, I am looking for a mapping that will cancel this if they will be executed one by one.

I am having trouble figuring out how to limit this new operation to working only on spaces before the first regular character.

+4
source share
2 answers

The following replacement command returns the effect of its copy, doubling the leading spaces.

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

The mapping that should be built for this command should follow the same as the one used in the question (except of course, replacement). To reduce repetition in definitions, you can split state-saving 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 
+5
source

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

 %s#^\s*#&&# 

And here is my suggested reverse replacement (take a deep breath ...):

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

Suppose the matched string ( submatch(0) ) contains n whitespace characters. What I'm doing is calculating half that number ( n/2 = string(float2nr(len(submatch(0))/2)) ) and then extracting a lot of characters from the match (essentially matchstr(n/2) ). This ensures that we get exactly half the space we started with (which can be a mixture of spaces and tabs).

If you know that a space will contain ONLY spaces or ONLY tabs, this can be somewhat simplified, for example:

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

In 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 reliable way to maintain cursor position and registration. Then you can map these functions as you like:

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

Hope this helps!

+2
source

Source: https://habr.com/ru/post/1394461/


All Articles