4

有人可以告诉我如何在 Vim 中做与此映射相反的操作:

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

澄清一下:此映射将(&& 部分)每行开头的空白字符数加倍。只有第一个常规字符之前的空格会受到影响。当前搜索字符串保持完整(通过_s 变量)。_s2 在此转换后(通过变量)恢复光标位置。

所以,基本上,我正在寻找一个映射,如果它们一个接一个地执行,它将撤消这个映射。

我在弄清楚如何将这个新操作限制为仅在第一个常规字符之前的空格上工作时遇到了麻烦。

4

2 回答 2

6

以下替换命令反转了其对应项的效果,该命令将前导空格加倍。

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

为该命令构建的映射需要遵循与问题中使用的相同的模式(当然,要执行的替换除外)。为了减少定义中的重复,可以将保持状态的代码分成一个小函数:

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
于 2012-02-03T06:48:57.210 回答
2

您的原始替换是这样的(为了便于阅读,我已将/分隔符替换#为):

%s#^\s*#&&#

这是我提出的反向替换(深呼吸......):

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

假设匹配的字符串 ( submatch(0)) 包含n空格字符。我正在做的是计算这个数字的一​​半(n/2= string(float2nr(len(submatch(0))/2))),然后从匹配中提取那么多字符(基本上matchstr(n/2))。这确保我们得到的空白正好是我们开始时的一半(可能是空格和制表符的混合)。

如果您知道空格将仅包含空格或仅包含制表符,则可以稍微简化一下,例如:

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

另一方面,我建议重新设计您的地图以使其更具可读性,从而更易于修改和维护。我的方法是定义两个函数:

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

请注意,这些get/set pos/reg函数是维护光标位置和寄存器的更强大的方法。然后,您可以根据需要映射这些函数:

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

希望有帮助!

于 2012-02-02T20:35:15.033 回答