在Vim中使用Preserve函数调用的奇怪循环行为

时间:2014-11-01 16:02:30

标签: vim

我在Vim中使用了从Vimcasts到preserve the cursor position when executing a command的函数:

" A command to preserve last search and cursor position after running another
" command.  See: http://vimcasts.org/episodes/tidying-whitespace/
function! Preserve(command)
  " Preparation: save last search, and cursor position.
  let _s=@/
  let l = line(".")
  let c = col(".")
  " Do the business:
  execute a:command
  " Clean up: restore previous search history, and cursor position
  let @/=_s
  call cursor(l, c)
endfunction

" Strip trailing whitespace
nmap <Leader>$ :call Preserve("%s/\\s\\+$//e")<CR>

对于我在这里显示的条带尾随空白映射,它的效果非常好,但是当我调用这样的外部命令时却没有:

" Reformat a plain text document to use hard wrapping and uniform spacing
"   Note: This uses the BSD `fmt` program.  The GNU coreutils version takes
"   different options.
nmap <Leader>f :call Preserve("%!fmt -s -78")<CR>
vnoremap <Leader>f :call Preserve("'<,'>!fmt -s -78")<CR>

第一个映射工作正常,但第二个映射表现出奇怪的循环行为。例如,如果我有这样的文本文件:

Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut laboret dolore magna aliqua. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

Sed ut perspiciatis unde omnis iste natus error sit. Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?

At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga.  Itaque reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus asperiores repellat.

当我在可视模式下选择这些行来过滤它们时,该命令似乎运行五次。这是我在输出中看到的内容:

5 lines filtered
5 lines filtered
5 lines filtered
5 lines filtered
5 lines filtered
Press ENTER or type command to continue

如果文件有10行,则会过滤10次。它仍然正确地过滤了该区域,但我很困惑为什么它循环。我认为它与Preserve函数有关,因为在preserve之外运行命令不会显示循环。

注意:我认为这是适合这个问题的地方,但是closing of the Vi/Vim proposal让我想知道我应该在哪里发布这样的问题。如果有更合适的论坛,请告诉我。

1 个答案:

答案 0 :(得分:2)

在多行视觉选择上调用函数时,将为选择中的每一行调用该函数。由于您的视觉选择涵盖5行,Preserve()函数,您传递给它的命令被调用5次。

解决方案很简单,将range参数添加到函数定义中:

function! Preserve() range

使用该参数,该函数只被调用一次,您可以让它或底层命令处理可视范围本身。

请参阅:help func-range

另一个 - 稍微脏一点 - 解决方案可能是在调用函数之前修改映射以删除范围,以便只调用它一次:

map <key> :<C-u>call Function(args)<CR>

请参阅:help c_ctrl-u